summaryrefslogtreecommitdiffstats
path: root/luni/src/main/native
diff options
context:
space:
mode:
Diffstat (limited to 'luni/src/main/native')
-rw-r--r--luni/src/main/native/cbigint.c875
-rw-r--r--luni/src/main/native/cbigint.h62
-rw-r--r--luni/src/main/native/commonDblParce.c606
-rw-r--r--luni/src/main/native/commonDblParce.h32
-rw-r--r--luni/src/main/native/fltconst.h156
-rw-r--r--luni/src/main/native/hycomp.h452
-rw-r--r--luni/src/main/native/java_io_File.c704
-rw-r--r--luni/src/main/native/java_io_FileDescriptor.c214
-rw-r--r--luni/src/main/native/java_io_ObjectInputStream.c287
-rw-r--r--luni/src/main/native/java_io_ObjectOutputStream.c246
-rw-r--r--luni/src/main/native/java_io_ObjectStreamClass.c134
-rw-r--r--luni/src/main/native/java_lang_Character.cpp75
-rw-r--r--luni/src/main/native/java_lang_Double.c77
-rw-r--r--luni/src/main/native/java_lang_Float.c85
-rw-r--r--luni/src/main/native/java_lang_Math.c204
-rw-r--r--luni/src/main/native/java_lang_StrictMath.c229
-rw-r--r--luni/src/main/native/java_net_InetAddress.cpp326
-rw-r--r--luni/src/main/native/java_net_NetworkInterface.c844
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp807
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp582
-rwxr-xr-xluni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp3637
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_util_NumberConvert.c291
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_util_fltparse.c609
-rw-r--r--luni/src/main/native/sub.mk34
24 files changed, 11568 insertions, 0 deletions
diff --git a/luni/src/main/native/cbigint.c b/luni/src/main/native/cbigint.c
new file mode 100644
index 0000000..0f65ca0
--- /dev/null
+++ b/luni/src/main/native/cbigint.c
@@ -0,0 +1,875 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include "cbigint.h"
+
+#if defined(LINUX) || defined(FREEBSD)
+#define USE_LL
+#endif
+
+#ifdef HY_LITTLE_ENDIAN
+#define at(i) (i)
+#else
+#define at(i) ((i)^1)
+/* the sequence for halfAt is -1, 2, 1, 4, 3, 6, 5, 8... */
+/* and it should correspond to 0, 1, 2, 3, 4, 5, 6, 7... */
+#define halfAt(i) (-((-(i)) ^ 1))
+#endif
+
+#define HIGH_IN_U64(u64) ((u64) >> 32)
+#if defined(USE_LL)
+#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFFLL)
+#else
+#if defined(USE_L)
+#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFFL)
+#else
+#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFF)
+#endif /* USE_L */
+#endif /* USE_LL */
+
+#if defined(USE_LL)
+#define TEN_E1 (0xALL)
+#define TEN_E2 (0x64LL)
+#define TEN_E3 (0x3E8LL)
+#define TEN_E4 (0x2710LL)
+#define TEN_E5 (0x186A0LL)
+#define TEN_E6 (0xF4240LL)
+#define TEN_E7 (0x989680LL)
+#define TEN_E8 (0x5F5E100LL)
+#define TEN_E9 (0x3B9ACA00LL)
+#define TEN_E19 (0x8AC7230489E80000LL)
+#else
+#if defined(USE_L)
+#define TEN_E1 (0xAL)
+#define TEN_E2 (0x64L)
+#define TEN_E3 (0x3E8L)
+#define TEN_E4 (0x2710L)
+#define TEN_E5 (0x186A0L)
+#define TEN_E6 (0xF4240L)
+#define TEN_E7 (0x989680L)
+#define TEN_E8 (0x5F5E100L)
+#define TEN_E9 (0x3B9ACA00L)
+#define TEN_E19 (0x8AC7230489E80000L)
+#else
+#define TEN_E1 (0xA)
+#define TEN_E2 (0x64)
+#define TEN_E3 (0x3E8)
+#define TEN_E4 (0x2710)
+#define TEN_E5 (0x186A0)
+#define TEN_E6 (0xF4240)
+#define TEN_E7 (0x989680)
+#define TEN_E8 (0x5F5E100)
+#define TEN_E9 (0x3B9ACA00)
+#define TEN_E19 (0x8AC7230489E80000)
+#endif /* USE_L */
+#endif /* USE_LL */
+
+#define TIMES_TEN(x) (((x) << 3) + ((x) << 1))
+#define bitSection(x, mask, shift) (((x) & (mask)) >> (shift))
+#define DOUBLE_TO_LONGBITS(dbl) (*((U_64 *)(&dbl)))
+#define FLOAT_TO_INTBITS(flt) (*((U_32 *)(&flt)))
+#define CREATE_DOUBLE_BITS(normalizedM, e) (((normalizedM) & MANTISSA_MASK) | (((U_64)((e) + E_OFFSET)) << 52))
+
+#if defined(USE_LL)
+#define MANTISSA_MASK (0x000FFFFFFFFFFFFFLL)
+#define EXPONENT_MASK (0x7FF0000000000000LL)
+#define NORMAL_MASK (0x0010000000000000LL)
+#define SIGN_MASK (0x8000000000000000LL)
+#else
+#if defined(USE_L)
+#define MANTISSA_MASK (0x000FFFFFFFFFFFFFL)
+#define EXPONENT_MASK (0x7FF0000000000000L)
+#define NORMAL_MASK (0x0010000000000000L)
+#define SIGN_MASK (0x8000000000000000L)
+#else
+#define MANTISSA_MASK (0x000FFFFFFFFFFFFF)
+#define EXPONENT_MASK (0x7FF0000000000000)
+#define NORMAL_MASK (0x0010000000000000)
+#define SIGN_MASK (0x8000000000000000)
+#endif /* USE_L */
+#endif /* USE_LL */
+
+#define E_OFFSET (1075)
+
+#define FLOAT_MANTISSA_MASK (0x007FFFFF)
+#define FLOAT_EXPONENT_MASK (0x7F800000)
+#define FLOAT_NORMAL_MASK (0x00800000)
+#define FLOAT_E_OFFSET (150)
+
+IDATA
+simpleAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2)
+{
+ /* assumes length > 0 */
+ IDATA index = 1;
+
+ *arg1 += arg2;
+ if (arg2 <= *arg1)
+ return 0;
+ else if (length == 1)
+ return 1;
+
+ while (++arg1[index] == 0 && ++index < length);
+
+ return (IDATA) index == length;
+}
+
+IDATA
+addHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
+{
+ /* addition is limited by length of arg1 as it this function is
+ * storing the result in arg1 */
+ /* fix for cc (GCC) 3.2 20020903 (Red Hat Linux 8.0 3.2-7): code generated does not
+ * do the temp1 + temp2 + carry addition correct. carry is 64 bit because gcc has
+ * subtle issues when you mix 64 / 32 bit maths. */
+ U_64 temp1, temp2, temp3; /* temporary variables to help the SH-4, and gcc */
+ U_64 carry;
+ IDATA index;
+
+ if (length1 == 0 || length2 == 0)
+ {
+ return 0;
+ }
+ else if (length1 < length2)
+ {
+ length2 = length1;
+ }
+
+ carry = 0;
+ index = 0;
+ do
+ {
+ temp1 = arg1[index];
+ temp2 = arg2[index];
+ temp3 = temp1 + temp2;
+ arg1[index] = temp3 + carry;
+ if (arg2[index] < arg1[index])
+ carry = 0;
+ else if (arg2[index] != arg1[index])
+ carry = 1;
+ }
+ while (++index < length2);
+ if (!carry)
+ return 0;
+ else if (index == length1)
+ return 1;
+
+ while (++arg1[index] == 0 && ++index < length1);
+
+ return (IDATA) index == length1;
+}
+
+void
+subtractHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
+{
+ /* assumes arg1 > arg2 */
+ IDATA index;
+ for (index = 0; index < length1; ++index)
+ arg1[index] = ~arg1[index];
+ simpleAddHighPrecision (arg1, length1, 1);
+
+ while (length2 > 0 && arg2[length2 - 1] == 0)
+ --length2;
+
+ addHighPrecision (arg1, length1, arg2, length2);
+
+ for (index = 0; index < length1; ++index)
+ arg1[index] = ~arg1[index];
+ simpleAddHighPrecision (arg1, length1, 1);
+}
+
+U_32
+simpleMultiplyHighPrecision (U_64 * arg1, IDATA length, U_64 arg2)
+{
+ /* assumes arg2 only holds 32 bits of information */
+ U_64 product;
+ IDATA index;
+
+ index = 0;
+ product = 0;
+
+ do
+ {
+ product =
+ HIGH_IN_U64 (product) + arg2 * LOW_U32_FROM_PTR (arg1 + index);
+ LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product);
+ product =
+ HIGH_IN_U64 (product) + arg2 * HIGH_U32_FROM_PTR (arg1 + index);
+ HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product);
+ }
+ while (++index < length);
+
+ return HIGH_U32_FROM_VAR (product);
+}
+
+void
+simpleMultiplyAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2,
+ U_32 * result)
+{
+ /* Assumes result can hold the product and arg2 only holds 32 bits
+ of information */
+ U_64 product;
+ IDATA index, resultIndex;
+
+ index = resultIndex = 0;
+ product = 0;
+
+ do
+ {
+ product =
+ HIGH_IN_U64 (product) + result[at (resultIndex)] +
+ arg2 * LOW_U32_FROM_PTR (arg1 + index);
+ result[at (resultIndex)] = LOW_U32_FROM_VAR (product);
+ ++resultIndex;
+ product =
+ HIGH_IN_U64 (product) + result[at (resultIndex)] +
+ arg2 * HIGH_U32_FROM_PTR (arg1 + index);
+ result[at (resultIndex)] = LOW_U32_FROM_VAR (product);
+ ++resultIndex;
+ }
+ while (++index < length);
+
+ result[at (resultIndex)] += HIGH_U32_FROM_VAR (product);
+ if (result[at (resultIndex)] < HIGH_U32_FROM_VAR (product))
+ {
+ /* must be careful with ++ operator and macro expansion */
+ ++resultIndex;
+ while (++result[at (resultIndex)] == 0)
+ ++resultIndex;
+ }
+}
+
+void
+multiplyHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2,
+ U_64 * result, IDATA length)
+{
+ /* assumes result is large enough to hold product */
+ U_64 *temp;
+ U_32 *resultIn32;
+ IDATA count, index;
+
+ if (length1 < length2)
+ {
+ temp = arg1;
+ arg1 = arg2;
+ arg2 = temp;
+ count = length1;
+ length1 = length2;
+ length2 = count;
+ }
+
+ memset (result, 0, sizeof (U_64) * length);
+
+ /* length1 > length2 */
+ resultIn32 = (U_32 *) result;
+ index = -1;
+ for (count = 0; count < length2; ++count)
+ {
+ simpleMultiplyAddHighPrecision (arg1, length1, LOW_IN_U64 (arg2[count]),
+ resultIn32 + (++index));
+ simpleMultiplyAddHighPrecision (arg1, length1,
+ HIGH_IN_U64 (arg2[count]),
+ resultIn32 + (++index));
+
+ }
+}
+
+U_32
+simpleAppendDecimalDigitHighPrecision (U_64 * arg1, IDATA length, U_64 digit)
+{
+ /* assumes digit is less than 32 bits */
+ U_64 arg;
+ IDATA index = 0;
+
+ digit <<= 32;
+ do
+ {
+ arg = LOW_IN_U64 (arg1[index]);
+ digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg);
+ LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit);
+
+ arg = HIGH_IN_U64 (arg1[index]);
+ digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg);
+ HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit);
+ }
+ while (++index < length);
+
+ return HIGH_U32_FROM_VAR (digit);
+}
+
+void
+simpleShiftLeftHighPrecision (U_64 * arg1, IDATA length, IDATA arg2)
+{
+ /* assumes length > 0 */
+ IDATA index, offset;
+ if (arg2 >= 64)
+ {
+ offset = arg2 >> 6;
+ index = length;
+
+ while (--index - offset >= 0)
+ arg1[index] = arg1[index - offset];
+ do
+ {
+ arg1[index] = 0;
+ }
+ while (--index >= 0);
+
+ arg2 &= 0x3F;
+ }
+
+ if (arg2 == 0)
+ return;
+ while (--length > 0)
+ {
+ arg1[length] = arg1[length] << arg2 | arg1[length - 1] >> (64 - arg2);
+ }
+ *arg1 <<= arg2;
+}
+
+IDATA
+highestSetBit (U_64 * y)
+{
+ U_32 x;
+ IDATA result;
+
+ if (*y == 0)
+ return 0;
+
+#if defined(USE_LL)
+ if (*y & 0xFFFFFFFF00000000LL)
+ {
+ x = HIGH_U32_FROM_PTR (y);
+ result = 32;
+ }
+ else
+ {
+ x = LOW_U32_FROM_PTR (y);
+ result = 0;
+ }
+#else
+#if defined(USE_L)
+ if (*y & 0xFFFFFFFF00000000L)
+ {
+ x = HIGH_U32_FROM_PTR (y);
+ result = 32;
+ }
+ else
+ {
+ x = LOW_U32_FROM_PTR (y);
+ result = 0;
+ }
+#else
+ if (*y & 0xFFFFFFFF00000000)
+ {
+ x = HIGH_U32_FROM_PTR (y);
+ result = 32;
+ }
+ else
+ {
+ x = LOW_U32_FROM_PTR (y);
+ result = 0;
+ }
+#endif /* USE_L */
+#endif /* USE_LL */
+
+ if (x & 0xFFFF0000)
+ {
+ x = bitSection (x, 0xFFFF0000, 16);
+ result += 16;
+ }
+ if (x & 0xFF00)
+ {
+ x = bitSection (x, 0xFF00, 8);
+ result += 8;
+ }
+ if (x & 0xF0)
+ {
+ x = bitSection (x, 0xF0, 4);
+ result += 4;
+ }
+ if (x > 0x7)
+ return result + 4;
+ else if (x > 0x3)
+ return result + 3;
+ else if (x > 0x1)
+ return result + 2;
+ else
+ return result + 1;
+}
+
+IDATA
+lowestSetBit (U_64 * y)
+{
+ U_32 x;
+ IDATA result;
+
+ if (*y == 0)
+ return 0;
+
+#if defined(USE_LL)
+ if (*y & 0x00000000FFFFFFFFLL)
+ {
+ x = LOW_U32_FROM_PTR (y);
+ result = 0;
+ }
+ else
+ {
+ x = HIGH_U32_FROM_PTR (y);
+ result = 32;
+ }
+#else
+#if defined(USE_L)
+ if (*y & 0x00000000FFFFFFFFL)
+ {
+ x = LOW_U32_FROM_PTR (y);
+ result = 0;
+ }
+ else
+ {
+ x = HIGH_U32_FROM_PTR (y);
+ result = 32;
+ }
+#else
+ if (*y & 0x00000000FFFFFFFF)
+ {
+ x = LOW_U32_FROM_PTR (y);
+ result = 0;
+ }
+ else
+ {
+ x = HIGH_U32_FROM_PTR (y);
+ result = 32;
+ }
+#endif /* USE_L */
+#endif /* USE_LL */
+
+ if (!(x & 0xFFFF))
+ {
+ x = bitSection (x, 0xFFFF0000, 16);
+ result += 16;
+ }
+ if (!(x & 0xFF))
+ {
+ x = bitSection (x, 0xFF00, 8);
+ result += 8;
+ }
+ if (!(x & 0xF))
+ {
+ x = bitSection (x, 0xF0, 4);
+ result += 4;
+ }
+
+ if (x & 0x1)
+ return result + 1;
+ else if (x & 0x2)
+ return result + 2;
+ else if (x & 0x4)
+ return result + 3;
+ else
+ return result + 4;
+}
+
+IDATA
+highestSetBitHighPrecision (U_64 * arg, IDATA length)
+{
+ IDATA highBit;
+
+ while (--length >= 0)
+ {
+ highBit = highestSetBit (arg + length);
+ if (highBit)
+ return highBit + 64 * length;
+ }
+
+ return 0;
+}
+
+IDATA
+lowestSetBitHighPrecision (U_64 * arg, IDATA length)
+{
+ IDATA lowBit, index = -1;
+
+ while (++index < length)
+ {
+ lowBit = lowestSetBit (arg + index);
+ if (lowBit)
+ return lowBit + 64 * index;
+ }
+
+ return 0;
+}
+
+IDATA
+compareHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
+{
+ while (--length1 >= 0 && arg1[length1] == 0);
+ while (--length2 >= 0 && arg2[length2] == 0);
+
+ if (length1 > length2)
+ return 1;
+ else if (length1 < length2)
+ return -1;
+ else if (length1 > -1)
+ {
+ do
+ {
+ if (arg1[length1] > arg2[length1])
+ return 1;
+ else if (arg1[length1] < arg2[length1])
+ return -1;
+ }
+ while (--length1 >= 0);
+ }
+
+ return 0;
+}
+
+jdouble
+toDoubleHighPrecision (U_64 * arg, IDATA length)
+{
+ IDATA highBit;
+ U_64 mantissa, test64;
+ U_32 test;
+ jdouble result;
+
+ while (length > 0 && arg[length - 1] == 0)
+ --length;
+
+ if (length == 0)
+ result = 0.0;
+ else if (length > 16)
+ {
+ DOUBLE_TO_LONGBITS (result) = EXPONENT_MASK;
+ }
+ else if (length == 1)
+ {
+ highBit = highestSetBit (arg);
+ if (highBit <= 53)
+ {
+ highBit = 53 - highBit;
+ mantissa = *arg << highBit;
+ DOUBLE_TO_LONGBITS (result) =
+ CREATE_DOUBLE_BITS (mantissa, -highBit);
+ }
+ else
+ {
+ highBit -= 53;
+ mantissa = *arg >> highBit;
+ DOUBLE_TO_LONGBITS (result) =
+ CREATE_DOUBLE_BITS (mantissa, highBit);
+
+ /* perform rounding, round to even in case of tie */
+ test = (LOW_U32_FROM_PTR (arg) << (11 - highBit)) & 0x7FF;
+ if (test > 0x400 || ((test == 0x400) && (mantissa & 1)))
+ DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
+ }
+ }
+ else
+ {
+ highBit = highestSetBit (arg + (--length));
+ if (highBit <= 53)
+ {
+ highBit = 53 - highBit;
+ if (highBit > 0)
+ {
+ mantissa =
+ (arg[length] << highBit) | (arg[length - 1] >>
+ (64 - highBit));
+ }
+ else
+ {
+ mantissa = arg[length];
+ }
+ DOUBLE_TO_LONGBITS (result) =
+ CREATE_DOUBLE_BITS (mantissa, length * 64 - highBit);
+
+ /* perform rounding, round to even in case of tie */
+ test64 = arg[--length] << highBit;
+ if (test64 > SIGN_MASK || ((test64 == SIGN_MASK) && (mantissa & 1)))
+ DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
+ else if (test64 == SIGN_MASK)
+ {
+ while (--length >= 0)
+ {
+ if (arg[length] != 0)
+ {
+ DOUBLE_TO_LONGBITS (result) =
+ DOUBLE_TO_LONGBITS (result) + 1;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ highBit -= 53;
+ mantissa = arg[length] >> highBit;
+ DOUBLE_TO_LONGBITS (result) =
+ CREATE_DOUBLE_BITS (mantissa, length * 64 + highBit);
+
+ /* perform rounding, round to even in case of tie */
+ test = (LOW_U32_FROM_PTR (arg + length) << (11 - highBit)) & 0x7FF;
+ if (test > 0x400 || ((test == 0x400) && (mantissa & 1)))
+ DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
+ else if (test == 0x400)
+ {
+ do
+ {
+ if (arg[--length] != 0)
+ {
+ DOUBLE_TO_LONGBITS (result) =
+ DOUBLE_TO_LONGBITS (result) + 1;
+ break;
+ }
+ }
+ while (length > 0);
+ }
+ }
+ }
+
+ return result;
+}
+
+IDATA
+tenToTheEHighPrecision (U_64 * result, IDATA length, jint e)
+{
+ /* size test */
+ if (length < ((e / 19) + 1))
+ return 0;
+
+ memset (result, 0, length * sizeof (U_64));
+ *result = 1;
+
+ if (e == 0)
+ return 1;
+
+ length = 1;
+ length = timesTenToTheEHighPrecision (result, length, e);
+ /* bad O(n) way of doing it, but simple */
+ /*
+ do {
+ overflow = simpleAppendDecimalDigitHighPrecision(result, length, 0);
+ if (overflow)
+ result[length++] = overflow;
+ } while (--e);
+ */
+ return length;
+}
+
+IDATA
+timesTenToTheEHighPrecision (U_64 * result, IDATA length, jint e)
+{
+ /* assumes result can hold value */
+ U_64 overflow;
+ int exp10 = e;
+
+ if (e == 0)
+ return length;
+
+ /* bad O(n) way of doing it, but simple */
+ /*
+ do {
+ overflow = simpleAppendDecimalDigitHighPrecision(result, length, 0);
+ if (overflow)
+ result[length++] = overflow;
+ } while (--e);
+ */
+ /* Replace the current implementaion which performs a
+ * "multiplication" by 10 e number of times with an actual
+ * mulitplication. 10e19 is the largest exponent to the power of ten
+ * that will fit in a 64-bit integer, and 10e9 is the largest exponent to
+ * the power of ten that will fit in a 64-bit integer. Not sure where the
+ * break-even point is between an actual multiplication and a
+ * simpleAappendDecimalDigit() so just pick 10e3 as that point for
+ * now.
+ */
+ while (exp10 >= 19)
+ {
+ overflow = simpleMultiplyHighPrecision64 (result, length, TEN_E19);
+ if (overflow)
+ result[length++] = overflow;
+ exp10 -= 19;
+ }
+ while (exp10 >= 9)
+ {
+ overflow = simpleMultiplyHighPrecision (result, length, TEN_E9);
+ if (overflow)
+ result[length++] = overflow;
+ exp10 -= 9;
+ }
+ if (exp10 == 0)
+ return length;
+ else if (exp10 == 1)
+ {
+ overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ else if (exp10 == 2)
+ {
+ overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
+ if (overflow)
+ result[length++] = overflow;
+ overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ else if (exp10 == 3)
+ {
+ overflow = simpleMultiplyHighPrecision (result, length, TEN_E3);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ else if (exp10 == 4)
+ {
+ overflow = simpleMultiplyHighPrecision (result, length, TEN_E4);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ else if (exp10 == 5)
+ {
+ overflow = simpleMultiplyHighPrecision (result, length, TEN_E5);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ else if (exp10 == 6)
+ {
+ overflow = simpleMultiplyHighPrecision (result, length, TEN_E6);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ else if (exp10 == 7)
+ {
+ overflow = simpleMultiplyHighPrecision (result, length, TEN_E7);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ else if (exp10 == 8)
+ {
+ overflow = simpleMultiplyHighPrecision (result, length, TEN_E8);
+ if (overflow)
+ result[length++] = overflow;
+ }
+ return length;
+}
+
+U_64
+doubleMantissa (jdouble z)
+{
+ U_64 m = DOUBLE_TO_LONGBITS (z);
+
+ if ((m & EXPONENT_MASK) != 0)
+ m = (m & MANTISSA_MASK) | NORMAL_MASK;
+ else
+ m = (m & MANTISSA_MASK);
+
+ return m;
+}
+
+IDATA
+doubleExponent (jdouble z)
+{
+ /* assumes positive double */
+ IDATA k = HIGH_U32_FROM_VAR (z) >> 20;
+
+ if (k)
+ k -= E_OFFSET;
+ else
+ k = 1 - E_OFFSET;
+
+ return k;
+}
+
+UDATA
+floatMantissa (jfloat z)
+{
+ UDATA m = (UDATA) FLOAT_TO_INTBITS (z);
+
+ if ((m & FLOAT_EXPONENT_MASK) != 0)
+ m = (m & FLOAT_MANTISSA_MASK) | FLOAT_NORMAL_MASK;
+ else
+ m = (m & FLOAT_MANTISSA_MASK);
+
+ return m;
+}
+
+IDATA
+floatExponent (jfloat z)
+{
+ /* assumes positive float */
+ IDATA k = FLOAT_TO_INTBITS (z) >> 23;
+ if (k)
+ k -= FLOAT_E_OFFSET;
+ else
+ k = 1 - FLOAT_E_OFFSET;
+
+ return k;
+}
+
+/* Allow a 64-bit value in arg2 */
+U_64
+simpleMultiplyHighPrecision64 (U_64 * arg1, IDATA length, U_64 arg2)
+{
+ U_64 intermediate, *pArg1, carry1, carry2, prod1, prod2, sum;
+ IDATA index;
+ U_32 buf32;
+
+ index = 0;
+ intermediate = 0;
+ pArg1 = arg1 + index;
+ carry1 = carry2 = 0;
+
+ do
+ {
+ if ((*pArg1 != 0) || (intermediate != 0))
+ {
+ prod1 =
+ (U_64) LOW_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1);
+ sum = intermediate + prod1;
+ if ((sum < prod1) || (sum < intermediate))
+ {
+ carry1 = 1;
+ }
+ else
+ {
+ carry1 = 0;
+ }
+ prod1 =
+ (U_64) LOW_U32_FROM_VAR (arg2) * (U_64) HIGH_U32_FROM_PTR (pArg1);
+ prod2 =
+ (U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1);
+ intermediate = carry2 + HIGH_IN_U64 (sum) + prod1 + prod2;
+ if ((intermediate < prod1) || (intermediate < prod2))
+ {
+ carry2 = 1;
+ }
+ else
+ {
+ carry2 = 0;
+ }
+ LOW_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (sum);
+ buf32 = HIGH_U32_FROM_PTR (pArg1);
+ HIGH_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (intermediate);
+ intermediate = carry1 + HIGH_IN_U64 (intermediate)
+ + (U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) buf32;
+ }
+ pArg1++;
+ }
+ while (++index < length);
+ return intermediate;
+}
diff --git a/luni/src/main/native/cbigint.h b/luni/src/main/native/cbigint.h
new file mode 100644
index 0000000..220aba8
--- /dev/null
+++ b/luni/src/main/native/cbigint.h
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(cbigint_h)
+#define cbigint_h
+#include "fltconst.h"
+#include "JNIHelp.h"
+#define LOW_U32_FROM_VAR(u64) LOW_U32_FROM_LONG64(u64)
+#define LOW_U32_FROM_PTR(u64ptr) LOW_U32_FROM_LONG64_PTR(u64ptr)
+#define HIGH_U32_FROM_VAR(u64) HIGH_U32_FROM_LONG64(u64)
+#define HIGH_U32_FROM_PTR(u64ptr) HIGH_U32_FROM_LONG64_PTR(u64ptr)
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+ void multiplyHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2,
+ IDATA length2, U_64 * result, IDATA length);
+ U_32 simpleAppendDecimalDigitHighPrecision (U_64 * arg1, IDATA length,
+ U_64 digit);
+ jdouble toDoubleHighPrecision (U_64 * arg, IDATA length);
+ IDATA tenToTheEHighPrecision (U_64 * result, IDATA length, jint e);
+ U_64 doubleMantissa (jdouble z);
+ IDATA compareHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2,
+ IDATA length2);
+ IDATA highestSetBitHighPrecision (U_64 * arg, IDATA length);
+ void subtractHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2,
+ IDATA length2);
+ IDATA doubleExponent (jdouble z);
+ U_32 simpleMultiplyHighPrecision (U_64 * arg1, IDATA length, U_64 arg2);
+ IDATA addHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2,
+ IDATA length2);
+ void simpleMultiplyAddHighPrecisionBigEndianFix (U_64 * arg1, IDATA length,
+ U_64 arg2, U_32 * result);
+ IDATA lowestSetBit (U_64 * y);
+ IDATA timesTenToTheEHighPrecision (U_64 * result, IDATA length, jint e);
+ void simpleMultiplyAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2,
+ U_32 * result);
+ IDATA highestSetBit (U_64 * y);
+ IDATA lowestSetBitHighPrecision (U_64 * arg, IDATA length);
+ void simpleShiftLeftHighPrecision (U_64 * arg1, IDATA length, IDATA arg2);
+ UDATA floatMantissa (jfloat z);
+ U_64 simpleMultiplyHighPrecision64 (U_64 * arg1, IDATA length, U_64 arg2);
+ IDATA simpleAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2);
+ IDATA floatExponent (jfloat z);
+#if defined(__cplusplus)
+}
+#endif
+#endif /* cbigint_h */
diff --git a/luni/src/main/native/commonDblParce.c b/luni/src/main/native/commonDblParce.c
new file mode 100644
index 0000000..5d85645
--- /dev/null
+++ b/luni/src/main/native/commonDblParce.c
@@ -0,0 +1,606 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdlib.h>
+#include <math.h>
+
+#include "commonDblParce.h"
+#include "cbigint.h"
+
+
+/* ************************* Defines ************************* */
+#if defined(LINUX) || defined(FREEBSD)
+#define USE_LL
+#endif
+
+#define LOW_I32_FROM_VAR(u64) LOW_I32_FROM_LONG64(u64)
+#define LOW_I32_FROM_PTR(u64ptr) LOW_I32_FROM_LONG64_PTR(u64ptr)
+#define HIGH_I32_FROM_VAR(u64) HIGH_I32_FROM_LONG64(u64)
+#define HIGH_I32_FROM_PTR(u64ptr) HIGH_I32_FROM_LONG64_PTR(u64ptr)
+
+#define MAX_ACCURACY_WIDTH 17
+
+#define DEFAULT_WIDTH MAX_ACCURACY_WIDTH
+
+#if defined(USE_LL)
+#define INFINITE_LONGBITS (0x7FF0000000000000LL)
+#else
+#if defined(USE_L)
+#define INFINITE_LONGBITS (0x7FF0000000000000L)
+#else
+#define INFINITE_LONGBITS (0x7FF0000000000000)
+#endif /* USE_L */
+#endif /* USE_LL */
+
+#define MINIMUM_LONGBITS (0x1)
+
+#if defined(USE_LL)
+#define MANTISSA_MASK (0x000FFFFFFFFFFFFFLL)
+#define EXPONENT_MASK (0x7FF0000000000000LL)
+#define NORMAL_MASK (0x0010000000000000LL)
+#else
+#if defined(USE_L)
+#define MANTISSA_MASK (0x000FFFFFFFFFFFFFL)
+#define EXPONENT_MASK (0x7FF0000000000000L)
+#define NORMAL_MASK (0x0010000000000000L)
+#else
+#define MANTISSA_MASK (0x000FFFFFFFFFFFFF)
+#define EXPONENT_MASK (0x7FF0000000000000)
+#define NORMAL_MASK (0x0010000000000000)
+#endif /* USE_L */
+#endif /* USE_LL */
+
+#define DOUBLE_TO_LONGBITS(dbl) (*((U_64 *)(&dbl)))
+
+/* Keep a count of the number of times we decrement and increment to
+ * approximate the double, and attempt to detect the case where we
+ * could potentially toggle back and forth between decrementing and
+ * incrementing. It is possible for us to be stuck in the loop when
+ * incrementing by one or decrementing by one may exceed or stay below
+ * the value that we are looking for. In this case, just break out of
+ * the loop if we toggle between incrementing and decrementing for more
+ * than twice.
+ */
+#define INCREMENT_DOUBLE(_x, _decCount, _incCount) \
+ { \
+ ++DOUBLE_TO_LONGBITS(_x); \
+ _incCount++; \
+ if( (_incCount > 2) && (_decCount > 2) ) { \
+ if( _decCount > _incCount ) { \
+ DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
+ } else if( _incCount > _decCount ) { \
+ DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
+ } \
+ break; \
+ } \
+ }
+#define DECREMENT_DOUBLE(_x, _decCount, _incCount) \
+ { \
+ --DOUBLE_TO_LONGBITS(_x); \
+ _decCount++; \
+ if( (_incCount > 2) && (_decCount > 2) ) { \
+ if( _decCount > _incCount ) { \
+ DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
+ } else if( _incCount > _decCount ) { \
+ DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
+ } \
+ break; \
+ } \
+ }
+
+#define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory;
+#define release(r) if ((r)) free((r));
+
+/* *********************************************************** */
+
+/* ************************ local data ************************ */
+static const jdouble tens[] = {
+ 1.0,
+ 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 function declarations ************** */
+static U_64 dblparse_shiftRight64 (U_64 * lp, volatile int mbe);
+
+static jdouble createDouble1 (JNIEnv * env, U_64 * f, IDATA length, jint e);
+static jdouble doubleAlgorithm (JNIEnv * env, U_64 * f, IDATA length, jint e,
+ jdouble z);
+/* *********************************************************** */
+
+#define tenToTheE(e) (*(tens + (e)))
+#define LOG5_OF_TWO_TO_THE_N 23
+
+#define sizeOfTenToTheE(e) (((e) / 19) + 1)
+
+jdouble
+createDouble (JNIEnv * env, const char *s, jint e)
+{
+ /* assumes s is a null terminated string with at least one
+ * character in it */
+ U_64 def[DEFAULT_WIDTH];
+ U_64 defBackup[DEFAULT_WIDTH];
+ U_64 *f, *fNoOverflow, *g, *tempBackup;
+ U_32 overflow;
+ jdouble result;
+ IDATA index = 1;
+ int unprocessedDigits = 0;
+
+ f = def;
+ fNoOverflow = defBackup;
+ *f = 0;
+ tempBackup = g = 0;
+ do
+ {
+ if (*s >= '0' && *s <= '9')
+ {
+ /* Make a back up of f before appending, so that we can
+ * back out of it if there is no more room, i.e. index >
+ * MAX_ACCURACY_WIDTH.
+ */
+ memcpy (fNoOverflow, f, sizeof (U_64) * index);
+ overflow =
+ simpleAppendDecimalDigitHighPrecision (f, index, *s - '0');
+ if (overflow)
+ {
+ f[index++] = overflow;
+ /* There is an overflow, but there is no more room
+ * to store the result. We really only need the top 52
+ * bits anyway, so we must back out of the overflow,
+ * and ignore the rest of the string.
+ */
+ if (index >= MAX_ACCURACY_WIDTH)
+ {
+ index--;
+ memcpy (f, fNoOverflow, sizeof (U_64) * index);
+ break;
+ }
+ if (tempBackup)
+ {
+ fNoOverflow = tempBackup;
+ }
+ }
+ }
+ else
+ index = -1;
+ }
+ while (index > 0 && *(++s) != '\0');
+
+ /* We've broken out of the parse loop either because we've reached
+ * the end of the string or we've overflowed the maximum accuracy
+ * limit of a double. If we still have unprocessed digits in the
+ * given string, then there are three possible results:
+ * 1. (unprocessed digits + e) == 0, in which case we simply
+ * convert the existing bits that are already parsed
+ * 2. (unprocessed digits + e) < 0, in which case we simply
+ * convert the existing bits that are already parsed along
+ * with the given e
+ * 3. (unprocessed digits + e) > 0 indicates that the value is
+ * simply too big to be stored as a double, so return Infinity
+ */
+ if ((unprocessedDigits = strlen (s)) > 0)
+ {
+ e += unprocessedDigits;
+ if (index > -1)
+ {
+ if (e == 0)
+ result = toDoubleHighPrecision (f, index);
+ else if (e < 0)
+ result = createDouble1 (env, f, index, e);
+ else
+ {
+ DOUBLE_TO_LONGBITS (result) = INFINITE_LONGBITS;
+ }
+ }
+ else
+ {
+ LOW_I32_FROM_VAR (result) = -1;
+ HIGH_I32_FROM_VAR (result) = -1;
+ }
+ }
+ else
+ {
+ if (index > -1)
+ {
+ if (e == 0)
+ result = toDoubleHighPrecision (f, index);
+ else
+ result = createDouble1 (env, f, index, e);
+ }
+ else
+ {
+ LOW_I32_FROM_VAR (result) = -1;
+ HIGH_I32_FROM_VAR (result) = -1;
+ }
+ }
+
+ return result;
+
+}
+
+jdouble
+createDouble1 (JNIEnv * env, U_64 * f, IDATA length, jint e)
+{
+ IDATA numBits;
+ jdouble result;
+
+#define APPROX_MIN_MAGNITUDE -309
+
+#define APPROX_MAX_MAGNITUDE 309
+
+ numBits = highestSetBitHighPrecision (f, length) + 1;
+ numBits -= lowestSetBitHighPrecision (f, length);
+ if (numBits < 54 && e >= 0 && e < LOG5_OF_TWO_TO_THE_N)
+ {
+ return toDoubleHighPrecision (f, length) * tenToTheE (e);
+ }
+ else if (numBits < 54 && e < 0 && (-e) < LOG5_OF_TWO_TO_THE_N)
+ {
+ return toDoubleHighPrecision (f, length) / tenToTheE (-e);
+ }
+ else if (e >= 0 && e < APPROX_MAX_MAGNITUDE)
+ {
+ result = toDoubleHighPrecision (f, length) * pow (10.0, e);
+ }
+ else if (e >= APPROX_MAX_MAGNITUDE)
+ {
+ /* Convert the partial result to make sure that the
+ * non-exponential part is not zero. This check fixes the case
+ * where the user enters 0.0e309! */
+ result = toDoubleHighPrecision (f, length);
+ /* Don't go straight to zero as the fact that x*0 = 0 independent of x might
+ cause the algorithm to produce an incorrect result. Instead try the min value
+ first and let it fall to zero if need be. */
+
+ if (result == 0.0)
+ {
+ DOUBLE_TO_LONGBITS (result) = MINIMUM_LONGBITS;
+ }
+ else
+ {
+ DOUBLE_TO_LONGBITS (result) = INFINITE_LONGBITS;
+ return result;
+ }
+ }
+ else if (e > APPROX_MIN_MAGNITUDE)
+ {
+ result = toDoubleHighPrecision (f, length) / pow (10.0, -e);
+ }
+
+ if (e <= APPROX_MIN_MAGNITUDE)
+ {
+
+ result = toDoubleHighPrecision (f, length) * pow (10.0, e + 52);
+ result = result * pow (10.0, -52);
+
+ }
+
+ /* Don't go straight to zero as the fact that x*0 = 0 independent of x might
+ cause the algorithm to produce an incorrect result. Instead try the min value
+ first and let it fall to zero if need be. */
+
+ if (result == 0.0)
+
+ DOUBLE_TO_LONGBITS (result) = MINIMUM_LONGBITS;
+
+ return doubleAlgorithm (env, f, length, e, result);
+}
+
+static U_64
+dblparse_shiftRight64 (U_64 * lp, volatile int mbe)
+{
+ U_64 b1Value = 0;
+ U_32 hi = HIGH_U32_FROM_LONG64_PTR (lp);
+ U_32 lo = LOW_U32_FROM_LONG64_PTR (lp);
+ int srAmt;
+
+ if (mbe == 0)
+ return 0;
+ if (mbe >= 128)
+ {
+ HIGH_U32_FROM_LONG64_PTR (lp) = 0;
+ LOW_U32_FROM_LONG64_PTR (lp) = 0;
+ return 0;
+ }
+
+ /* Certain platforms do not handle de-referencing a 64-bit value
+ * from a pointer on the stack correctly (e.g. MVL-hh/XScale)
+ * because the pointer may not be properly aligned, so we'll have
+ * to handle two 32-bit chunks. */
+ if (mbe < 32)
+ {
+ LOW_U32_FROM_LONG64 (b1Value) = 0;
+ HIGH_U32_FROM_LONG64 (b1Value) = lo << (32 - mbe);
+ LOW_U32_FROM_LONG64_PTR (lp) = (hi << (32 - mbe)) | (lo >> mbe);
+ HIGH_U32_FROM_LONG64_PTR (lp) = hi >> mbe;
+ }
+ else if (mbe == 32)
+ {
+ LOW_U32_FROM_LONG64 (b1Value) = 0;
+ HIGH_U32_FROM_LONG64 (b1Value) = lo;
+ LOW_U32_FROM_LONG64_PTR (lp) = hi;
+ HIGH_U32_FROM_LONG64_PTR (lp) = 0;
+ }
+ else if (mbe < 64)
+ {
+ srAmt = mbe - 32;
+ LOW_U32_FROM_LONG64 (b1Value) = lo << (32 - srAmt);
+ HIGH_U32_FROM_LONG64 (b1Value) = (hi << (32 - srAmt)) | (lo >> srAmt);
+ LOW_U32_FROM_LONG64_PTR (lp) = hi >> srAmt;
+ HIGH_U32_FROM_LONG64_PTR (lp) = 0;
+ }
+ else if (mbe == 64)
+ {
+ LOW_U32_FROM_LONG64 (b1Value) = lo;
+ HIGH_U32_FROM_LONG64 (b1Value) = hi;
+ LOW_U32_FROM_LONG64_PTR (lp) = 0;
+ HIGH_U32_FROM_LONG64_PTR (lp) = 0;
+ }
+ else if (mbe < 96)
+ {
+ srAmt = mbe - 64;
+ b1Value = *lp;
+ HIGH_U32_FROM_LONG64_PTR (lp) = 0;
+ LOW_U32_FROM_LONG64_PTR (lp) = 0;
+ LOW_U32_FROM_LONG64 (b1Value) >>= srAmt;
+ LOW_U32_FROM_LONG64 (b1Value) |= (hi << (32 - srAmt));
+ HIGH_U32_FROM_LONG64 (b1Value) >>= srAmt;
+ }
+ else if (mbe == 96)
+ {
+ LOW_U32_FROM_LONG64 (b1Value) = hi;
+ HIGH_U32_FROM_LONG64 (b1Value) = 0;
+ HIGH_U32_FROM_LONG64_PTR (lp) = 0;
+ LOW_U32_FROM_LONG64_PTR (lp) = 0;
+ }
+ else
+ {
+ LOW_U32_FROM_LONG64 (b1Value) = hi >> (mbe - 96);
+ HIGH_U32_FROM_LONG64 (b1Value) = 0;
+ HIGH_U32_FROM_LONG64_PTR (lp) = 0;
+ LOW_U32_FROM_LONG64_PTR (lp) = 0;
+ }
+
+ return b1Value;
+}
+
+#if defined(WIN32)
+/* disable global optimizations on the microsoft compiler for the
+ * doubleAlgorithm function otherwise it won't compile */
+#pragma optimize("g",off)
+#endif
+
+
+/* The algorithm for the function doubleAlgorithm() below can be found
+ * in:
+ *
+ * "How to Read Floating-Point Numbers Accurately", William D.
+ * Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
+ * Programming Language Design and Implementation, June 20-22,
+ * 1990, pp. 92-101.
+ *
+ * There is a possibility that the function will end up in an endless
+ * loop if the given approximating floating-point number (a very small
+ * floating-point whose value is very close to zero) straddles between
+ * two approximating integer values. We modified the algorithm slightly
+ * to detect the case where it oscillates back and forth between
+ * incrementing and decrementing the floating-point approximation. It
+ * is currently set such that if the oscillation occurs more than twice
+ * then return the original approximation.
+ */
+static jdouble
+doubleAlgorithm (JNIEnv * env, U_64 * f, IDATA length, jint e, jdouble z)
+{
+ U_64 m;
+ IDATA k, comparison, comparison2;
+ U_64 *x, *y, *D, *D2;
+ IDATA xLength, yLength, DLength, D2Length, decApproxCount, incApproxCount;
+
+ x = y = D = D2 = 0;
+ xLength = yLength = DLength = D2Length = 0;
+ decApproxCount = incApproxCount = 0;
+
+ do
+ {
+ m = doubleMantissa (z);
+ k = doubleExponent (z);
+
+ if (x && x != f)
+ free(x);
+
+ release (y);
+ release (D);
+ release (D2);
+
+ if (e >= 0 && k >= 0)
+ {
+ xLength = sizeOfTenToTheE (e) + length;
+ allocateU64 (x, xLength);
+ memset (x + length, 0, sizeof (U_64) * (xLength - length));
+ memcpy (x, f, sizeof (U_64) * length);
+ timesTenToTheEHighPrecision (x, xLength, e);
+
+ yLength = (k >> 6) + 2;
+ allocateU64 (y, yLength);
+ memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
+ *y = m;
+ simpleShiftLeftHighPrecision (y, yLength, k);
+ }
+ else if (e >= 0)
+ {
+ xLength = sizeOfTenToTheE (e) + length + ((-k) >> 6) + 1;
+ allocateU64 (x, xLength);
+ memset (x + length, 0, sizeof (U_64) * (xLength - length));
+ memcpy (x, f, sizeof (U_64) * length);
+ timesTenToTheEHighPrecision (x, xLength, e);
+ simpleShiftLeftHighPrecision (x, xLength, -k);
+
+ yLength = 1;
+ allocateU64 (y, 1);
+ *y = m;
+ }
+ else if (k >= 0)
+ {
+ xLength = length;
+ x = f;
+
+ yLength = sizeOfTenToTheE (-e) + 2 + (k >> 6);
+ allocateU64 (y, yLength);
+ memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
+ *y = m;
+ timesTenToTheEHighPrecision (y, yLength, -e);
+ simpleShiftLeftHighPrecision (y, yLength, k);
+ }
+ else
+ {
+ xLength = length + ((-k) >> 6) + 1;
+ allocateU64 (x, xLength);
+ memset (x + length, 0, sizeof (U_64) * (xLength - length));
+ memcpy (x, f, sizeof (U_64) * length);
+ simpleShiftLeftHighPrecision (x, xLength, -k);
+
+ yLength = sizeOfTenToTheE (-e) + 1;
+ allocateU64 (y, yLength);
+ memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
+ *y = m;
+ timesTenToTheEHighPrecision (y, yLength, -e);
+ }
+
+ comparison = compareHighPrecision (x, xLength, y, yLength);
+ if (comparison > 0)
+ { /* x > y */
+ DLength = xLength;
+ allocateU64 (D, DLength);
+ memcpy (D, x, DLength * sizeof (U_64));
+ subtractHighPrecision (D, DLength, y, yLength);
+ }
+ else if (comparison)
+ { /* y > x */
+ DLength = yLength;
+ allocateU64 (D, DLength);
+ memcpy (D, y, DLength * sizeof (U_64));
+ subtractHighPrecision (D, DLength, x, xLength);
+ }
+ else
+ { /* y == x */
+ DLength = 1;
+ allocateU64 (D, 1);
+ *D = 0;
+ }
+
+ D2Length = DLength + 1;
+ allocateU64 (D2, D2Length);
+ m <<= 1;
+ multiplyHighPrecision (D, DLength, &m, 1, D2, D2Length);
+ m >>= 1;
+
+ comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
+ if (comparison2 < 0)
+ {
+ if (comparison < 0 && m == NORMAL_MASK)
+ {
+ simpleShiftLeftHighPrecision (D2, D2Length, 1);
+ if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
+ {
+ DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else if (comparison2 == 0)
+ {
+ if ((LOW_U32_FROM_VAR (m) & 1) == 0)
+ {
+ if (comparison < 0 && m == NORMAL_MASK)
+ {
+ DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else if (comparison < 0)
+ {
+ DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ break;
+ }
+ else
+ {
+ INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ break;
+ }
+ }
+ else if (comparison < 0)
+ {
+ DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ }
+ else
+ {
+ if (DOUBLE_TO_LONGBITS (z) == INFINITE_LONGBITS)
+ break;
+ INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
+ }
+ }
+ while (1);
+
+ if (x && x != f)
+ free(x);
+ release (y);
+ release (D);
+ release (D2);
+ return z;
+
+OutOfMemory:
+ if (x && x != f)
+ free(x);
+ release (y);
+ release (y);
+ release (D);
+ release (D2);
+
+ DOUBLE_TO_LONGBITS (z) = -2;
+
+ return z;
+}
diff --git a/luni/src/main/native/commonDblParce.h b/luni/src/main/native/commonDblParce.h
new file mode 100644
index 0000000..d693910
--- /dev/null
+++ b/luni/src/main/native/commonDblParce.h
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <JNIHelp.h>
+/* Header for class org_apache_harmony_text_BidiWrapper */
+
+#if !defined(_Included_commonDblParce)
+#define _Included_commonDblFltParce
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+jdouble createDouble(JNIEnv * env, const char *s, jint e);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/luni/src/main/native/fltconst.h b/luni/src/main/native/fltconst.h
new file mode 100644
index 0000000..03a97cd
--- /dev/null
+++ b/luni/src/main/native/fltconst.h
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(fltconst_h)
+#define fltconst_h
+
+#include "hycomp.h"
+
+/* IEEE floats consist of: sign bit, exponent field, significand field
+ single: 31 = sign bit, 30..23 = exponent (8 bits), 22..0 = significand (23 bits)
+ double: 63 = sign bit, 62..52 = exponent (11 bits), 51..0 = significand (52 bits)
+ inf == (all exponent bits set) and (all mantissa bits clear)
+ nan == (all exponent bits set) and (at least one mantissa bit set)
+ finite == (at least one exponent bit clear)
+ zero == (all exponent bits clear) and (all mantissa bits clear)
+ denormal == (all exponent bits clear) and (at least one mantissa bit set)
+ positive == sign bit clear
+ negative == sign bit set
+*/
+#define MAX_U32_DOUBLE (ESDOUBLE) (4294967296.0) /* 2^32 */
+#define MAX_U32_SINGLE (ESSINGLE) (4294967296.0) /* 2^32 */
+#define HY_POS_PI (ESDOUBLE) (3.141592653589793)
+
+#ifdef HY_LITTLE_ENDIAN
+#ifdef HY_PLATFORM_DOUBLE_ORDER
+#define DOUBLE_LO_OFFSET 0
+#define DOUBLE_HI_OFFSET 1
+#else
+#define DOUBLE_LO_OFFSET 1
+#define DOUBLE_HI_OFFSET 0
+#endif
+#define LONG_LO_OFFSET 0
+#define LONG_HI_OFFSET 1
+#else
+#ifdef HY_PLATFORM_DOUBLE_ORDER
+#define DOUBLE_LO_OFFSET 1
+#define DOUBLE_HI_OFFSET 0
+#else
+#define DOUBLE_LO_OFFSET 0
+#define DOUBLE_HI_OFFSET 1
+#endif
+#define LONG_LO_OFFSET 1
+#define LONG_HI_OFFSET 0
+#endif
+
+#define RETURN_FINITE 0
+#define RETURN_NAN 1
+#define RETURN_POS_INF 2
+#define RETURN_NEG_INF 3
+#define DOUBLE_SIGN_MASK_HI 0x80000000
+#define DOUBLE_EXPONENT_MASK_HI 0x7FF00000
+#define DOUBLE_MANTISSA_MASK_LO 0xFFFFFFFF
+#define DOUBLE_MANTISSA_MASK_HI 0x000FFFFF
+#define SINGLE_SIGN_MASK 0x80000000
+#define SINGLE_EXPONENT_MASK 0x7F800000
+#define SINGLE_MANTISSA_MASK 0x007FFFFF
+#define SINGLE_NAN_BITS (SINGLE_EXPONENT_MASK | 0x00400000)
+
+typedef union u64u32dbl_tag {
+ U_64 u64val;
+ U_32 u32val[2];
+ I_32 i32val[2];
+ double dval;
+} U64U32DBL;
+
+/* Replace P_FLOAT_HI and P_FLOAT_LOW */
+/* These macros are used to access the high and low 32-bit parts of a double (64-bit) value. */
+#define LOW_U32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->u32val[DOUBLE_LO_OFFSET])
+#define HIGH_U32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->u32val[DOUBLE_HI_OFFSET])
+#define LOW_I32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->i32val[DOUBLE_LO_OFFSET])
+#define HIGH_I32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->i32val[DOUBLE_HI_OFFSET])
+#define LOW_U32_FROM_DBL(dbl) LOW_U32_FROM_DBL_PTR(&(dbl))
+#define HIGH_U32_FROM_DBL(dbl) HIGH_U32_FROM_DBL_PTR(&(dbl))
+#define LOW_I32_FROM_DBL(dbl) LOW_I32_FROM_DBL_PTR(&(dbl))
+#define HIGH_I32_FROM_DBL(dbl) HIGH_I32_FROM_DBL_PTR(&(dbl))
+#define LOW_U32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->u32val[LONG_LO_OFFSET])
+#define HIGH_U32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->u32val[LONG_HI_OFFSET])
+#define LOW_I32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->i32val[LONG_LO_OFFSET])
+#define HIGH_I32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->i32val[LONG_HI_OFFSET])
+#define LOW_U32_FROM_LONG64(long64) LOW_U32_FROM_LONG64_PTR(&(long64))
+#define HIGH_U32_FROM_LONG64(long64) HIGH_U32_FROM_LONG64_PTR(&(long64))
+#define LOW_I32_FROM_LONG64(long64) LOW_I32_FROM_LONG64_PTR(&(long64))
+#define HIGH_I32_FROM_LONG64(long64) HIGH_I32_FROM_LONG64_PTR(&(long64))
+#define IS_ZERO_DBL_PTR(dblptr) ((LOW_U32_FROM_DBL_PTR(dblptr) == 0) && ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0) || (HIGH_U32_FROM_DBL_PTR(dblptr) == DOUBLE_SIGN_MASK_HI)))
+#define IS_ONE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0x3ff00000 || HIGH_U32_FROM_DBL_PTR(dblptr) == 0xbff00000) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0))
+#define IS_NAN_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) == DOUBLE_EXPONENT_MASK_HI) && (LOW_U32_FROM_DBL_PTR(dblptr) | (HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_MANTISSA_MASK_HI)))
+#define IS_INF_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & (DOUBLE_EXPONENT_MASK_HI|DOUBLE_MANTISSA_MASK_HI)) == DOUBLE_EXPONENT_MASK_HI) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0))
+#define IS_DENORMAL_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) == 0) && ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_MANTISSA_MASK_HI) != 0 || (LOW_U32_FROM_DBL_PTR(dblptr) != 0)))
+#define IS_FINITE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) < DOUBLE_EXPONENT_MASK_HI)
+#define IS_POSITIVE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_SIGN_MASK_HI) == 0)
+#define IS_NEGATIVE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_SIGN_MASK_HI) != 0)
+#define IS_NEGATIVE_MAX_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0xFFEFFFFF) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0xFFFFFFFF))
+#define IS_ZERO_DBL(dbl) IS_ZERO_DBL_PTR(&(dbl))
+#define IS_ONE_DBL(dbl) IS_ONE_DBL_PTR(&(dbl))
+#define IS_NAN_DBL(dbl) IS_NAN_DBL_PTR(&(dbl))
+#define IS_INF_DBL(dbl) IS_INF_DBL_PTR(&(dbl))
+#define IS_DENORMAL_DBL(dbl) IS_DENORMAL_DBL_PTR(&(dbl))
+#define IS_FINITE_DBL(dbl) IS_FINITE_DBL_PTR(&(dbl))
+#define IS_POSITIVE_DBL(dbl) IS_POSITIVE_DBL_PTR(&(dbl))
+#define IS_NEGATIVE_DBL(dbl) IS_NEGATIVE_DBL_PTR(&(dbl))
+#define IS_NEGATIVE_MAX_DBL(dbl) IS_NEGATIVE_MAX_DBL_PTR(&(dbl))
+#define IS_ZERO_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) == (U_32)0)
+#define IS_ONE_SNGL_PTR(fltptr) ((*U32P((fltptr)) == 0x3f800000) || (*U32P((fltptr)) == 0xbf800000))
+#define IS_NAN_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) > (U_32)SINGLE_EXPONENT_MASK)
+#define IS_INF_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) == (U_32)SINGLE_EXPONENT_MASK)
+#define IS_DENORMAL_SNGL_PTR(fltptr) (((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK)-(U_32)1) < (U_32)SINGLE_MANTISSA_MASK)
+#define IS_FINITE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) < (U_32)SINGLE_EXPONENT_MASK)
+#define IS_POSITIVE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)SINGLE_SIGN_MASK) == (U_32)0)
+#define IS_NEGATIVE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)SINGLE_SIGN_MASK) != (U_32)0)
+#define IS_ZERO_SNGL(flt) IS_ZERO_SNGL_PTR(&(flt))
+#define IS_ONE_SNGL(flt) IS_ONE_SNGL_PTR(&(flt))
+#define IS_NAN_SNGL(flt) IS_NAN_SNGL_PTR(&(flt))
+#define IS_INF_SNGL(flt) IS_INF_SNGL_PTR(&(flt))
+#define IS_DENORMAL_SNGL(flt) IS_DENORMAL_SNGL_PTR(&(flt))
+#define IS_FINITE_SNGL(flt) IS_FINITE_SNGL_PTR(&(flt))
+#define IS_POSITIVE_SNGL(flt) IS_POSITIVE_SNGL_PTR(&(flt))
+#define IS_NEGATIVE_SNGL(flt) IS_NEGATIVE_SNGL_PTR(&(flt))
+#define SET_NAN_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = (DOUBLE_EXPONENT_MASK_HI | 0x00080000); LOW_U32_FROM_DBL_PTR(dblptr) = 0
+#define SET_PZERO_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = 0; LOW_U32_FROM_DBL_PTR(dblptr) = 0
+#define SET_NZERO_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = DOUBLE_SIGN_MASK_HI; LOW_U32_FROM_DBL_PTR(dblptr) = 0
+#define SET_PINF_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = DOUBLE_EXPONENT_MASK_HI; LOW_U32_FROM_DBL_PTR(dblptr) = 0
+#define SET_NINF_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = (DOUBLE_EXPONENT_MASK_HI | DOUBLE_SIGN_MASK_HI); LOW_U32_FROM_DBL_PTR(dblptr) = 0
+#define SET_NAN_SNGL_PTR(fltptr) *U32P((fltptr)) = ((U_32)SINGLE_NAN_BITS)
+#define SET_PZERO_SNGL_PTR(fltptr) *U32P((fltptr)) = 0
+#define SET_NZERO_SNGL_PTR(fltptr) *U32P((fltptr)) = SINGLE_SIGN_MASK
+#define SET_PINF_SNGL_PTR(fltptr) *U32P((fltptr)) = SINGLE_EXPONENT_MASK
+#define SET_NINF_SNGL_PTR(fltptr) *U32P((fltptr)) = (SINGLE_EXPONENT_MASK | SINGLE_SIGN_MASK)
+
+/* on some platforms (HP720) we cannot reference an unaligned float. Build them by hand, one U_32 at a time. */
+#if defined(ATOMIC_FLOAT_ACCESS)
+#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) HIGH_U32_FROM_DBL_PTR(dstPtr) = HIGH_U32_FROM_DBL_PTR(aDoublePtr); LOW_U32_FROM_DBL_PTR(dstPtr) = LOW_U32_FROM_DBL_PTR(aDoublePtr)
+#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) HIGH_U32_FROM_DBL_PTR(aDoublePtr) = HIGH_U32_FROM_DBL_PTR(dstPtr); LOW_U32_FROM_DBL_PTR(aDoublePtr) = LOW_U32_FROM_DBL_PTR(dstPtr)
+#else
+#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) (*(dstPtr) = *(aDoublePtr))
+#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) (*(aDoublePtr) = *(dstPtr))
+#endif
+
+#define STORE_LONG(dstPtr, hi, lo) HIGH_U32_FROM_LONG64_PTR(dstPtr) = (hi); LOW_U32_FROM_LONG64_PTR(dstPtr) = (lo)
+#define PTR_SINGLE_VALUE(dstPtr, aSinglePtr) (*U32P(aSinglePtr) = *U32P(dstPtr))
+#define PTR_SINGLE_STORE(dstPtr, aSinglePtr) *((U_32 *)(dstPtr)) = (*U32P(aSinglePtr))
+
+#endif /* fltconst_h */
diff --git a/luni/src/main/native/hycomp.h b/luni/src/main/native/hycomp.h
new file mode 100644
index 0000000..cd8ce73
--- /dev/null
+++ b/luni/src/main/native/hycomp.h
@@ -0,0 +1,452 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(hycomp_h)
+#define hycomp_h
+
+#if !defined(LINUX)
+#define LINUX 1
+#endif
+
+/**
+ * USE_PROTOTYPES: Use full ANSI prototypes.
+ *
+ * CLOCK_PRIMS: We want the timer/clock prims to be used
+ *
+ * LITTLE_ENDIAN: This is for the intel machines or other
+ * little endian processors. Defaults to big endian.
+ *
+ * NO_LVALUE_CASTING: This is for compilers that don't like the left side
+ * of assigns to be cast. It hacks around to do the
+ * right thing.
+ *
+ * ATOMIC_FLOAT_ACCESS: So that float operations will work.
+ *
+ * LINKED_USER_PRIMITIVES: Indicates that user primitives are statically linked
+ * with the VM executeable.
+ *
+ * OLD_SPACE_SIZE_DIFF: The 68k uses a different amount of old space.
+ * This "legitimizes" the change.
+ *
+ * SIMPLE_SIGNAL: For machines that don't use real signals in C.
+ * (eg: PC, 68k)
+ *
+ * OS_NAME_LOOKUP: Use nlist to lookup user primitive addresses.
+ *
+ * VMCALL: Tag for all functions called by the VM.
+ *
+ * VMAPICALL: Tag for all functions called via the PlatformFunction
+ * callWith: mechanism.
+ *
+ * SYS_FLOAT: For some math functions where extended types (80 or 96 bits) are returned
+ * Most platforms return as a double
+ *
+ * FLOAT_EXTENDED: If defined, the type name for extended precision floats.
+ *
+ * PLATFORM_IS_ASCII: Must be defined if the platform is ASCII
+ *
+ * EXE_EXTENSION_CHAR: the executable has a delimiter that we want to stop at as part of argv[0].
+ */
+
+ /**
+ * By default order doubles in the native (that is big/little endian) ordering.
+ */
+
+#define HY_PLATFORM_DOUBLE_ORDER
+
+/**
+ * Define common types:
+ * <ul>
+ * <li><code>U_32 / I_32</code> - unsigned/signed 32 bits</li>
+ * <li><code>U_16 / I_16</code> - unsigned/signed 16 bits</li>
+ * <li><code>U_8 / I_8</code> - unsigned/signed 8 bits (bytes -- not to be
+ * confused with char)</li>
+ * </ul>
+ */
+
+typedef int I_32;
+typedef short I_16;
+typedef signed char I_8; /* chars can be unsigned */
+typedef unsigned int U_32;
+typedef unsigned short U_16;
+typedef unsigned char U_8;
+
+/**
+ * Define platform specific types:
+ * <ul>
+ * <li><code>U_64 / I_64</code> - unsigned/signed 64 bits</li>
+ * </ul>
+ */
+
+#if defined(LINUX) || defined(FREEBSD) || defined(AIX)
+
+#define DATA_TYPES_DEFINED
+
+/* NOTE: Linux supports different processors -- do not assume 386 */
+ #if defined(HYX86_64) || defined(HYIA64) || defined(HYPPC64) || defined(HYS390X)
+
+ typedef unsigned long int U_64; /* 64bits */
+ typedef long int I_64;
+ #define TOC_UNWRAP_ADDRESS(wrappedPointer) ((void *) (wrappedPointer)[0])
+ #define TOC_STORE_TOC(dest,wrappedPointer) (dest = ((UDATA*)wrappedPointer)[1])
+
+ #define HY_WORD64
+
+ #else
+
+ typedef unsigned long long U_64;
+ typedef long long I_64;
+
+ #endif
+
+ #if defined(HYS390X) || defined(HYS390) || defined(HYPPC64) || defined(HYPPC32)
+ #define HY_BIG_ENDIAN
+ #else
+ #define HY_LITTLE_ENDIAN
+ #endif
+
+ #if defined(HYPPC32)
+ #define VA_PTR(valist) (&valist[0])
+ #endif
+
+ typedef double SYS_FLOAT;
+ #define HYCONST64(x) x##LL
+ #define NO_LVALUE_CASTING
+ #define FLOAT_EXTENDED long double
+ #define PLATFORM_IS_ASCII
+ #define PLATFORM_LINE_DELIMITER "\012"
+ #define DIR_SEPARATOR '/'
+ #define DIR_SEPARATOR_STR "/"
+
+/**
+ * No priorities on Linux
+ */
+
+ #define HY_PRIORITY_MAP {0,0,0,0,0,0,0,0,0,0,0,0}
+
+ typedef U_32 BOOLEAN;
+
+#endif
+
+/* Win32 - Windows 3.1 & NT using Win32 */
+#if defined(WIN32)
+
+ #define HY_LITTLE_ENDIAN
+
+/* Define 64-bit integers for Windows */
+ typedef __int64 I_64;
+ typedef unsigned __int64 U_64;
+
+ typedef double SYS_FLOAT;
+ #define NO_LVALUE_CASTING
+ #define VMAPICALL _stdcall
+ #define VMCALL _cdecl
+ #define EXE_EXTENSION_CHAR '.'
+
+ #define DIR_SEPARATOR '\\'
+ #define DIR_SEPARATOR_STR "\\"
+
+/* Modifications for the Alpha running WIN-NT */
+ #if defined(_ALPHA_)
+ #undef small /* defined as char in rpcndr.h */
+ typedef double FLOAT_EXTENDED;
+ #endif
+
+ #define HY_PRIORITY_MAP { \
+ THREAD_PRIORITY_IDLE, /* 0 */\
+ THREAD_PRIORITY_LOWEST, /* 1 */\
+ THREAD_PRIORITY_BELOW_NORMAL, /* 2 */\
+ THREAD_PRIORITY_BELOW_NORMAL, /* 3 */\
+ THREAD_PRIORITY_BELOW_NORMAL, /* 4 */\
+ THREAD_PRIORITY_NORMAL, /* 5 */\
+ THREAD_PRIORITY_ABOVE_NORMAL, /* 6 */\
+ THREAD_PRIORITY_ABOVE_NORMAL, /* 7 */\
+ THREAD_PRIORITY_ABOVE_NORMAL, /* 8 */\
+ THREAD_PRIORITY_ABOVE_NORMAL, /* 9 */\
+ THREAD_PRIORITY_HIGHEST, /*10 */\
+ THREAD_PRIORITY_TIME_CRITICAL /*11 */}
+
+#endif /* defined(WIN32) */
+
+#if !defined(VMCALL)
+ #define VMCALL
+ #define VMAPICALL
+#endif
+#define PVMCALL VMCALL *
+
+#define GLOBAL_DATA(symbol) ((void*)&(symbol))
+#define GLOBAL_TABLE(symbol) GLOBAL_DATA(symbol)
+
+/**
+ * Define platform specific types:
+ * <ul>
+ * <li><code>UDATA</code> - unsigned data, can be used as an integer or
+ * pointer storage</li>
+ * <li><code>IDATA</code> - signed data, can be used as an integer or
+ * pointer storage</li>
+ * </ul>
+ */
+/* FIXME: POINTER64 */
+#if defined(HYX86_64) || defined(HYIA64) || defined(HYPPC64) || defined(HYS390X) || defined(POINTER64)
+
+typedef I_64 IDATA;
+typedef U_64 UDATA;
+
+#else /* this is default for non-64bit systems */
+
+typedef I_32 IDATA;
+typedef U_32 UDATA;
+
+#endif /* defined(HYX86_64) */
+
+#if !defined(DATA_TYPES_DEFINED)
+/* no generic U_64 or I_64 */
+
+/* don't typedef BOOLEAN since it's already def'ed on Win32 */
+#define BOOLEAN UDATA
+
+#ifndef HY_BIG_ENDIAN
+#define HY_LITTLE_ENDIAN
+#endif
+
+#endif
+
+#if !defined(HYCONST64)
+#define HYCONST64(x) x##L
+#endif
+
+#if !defined(HY_DEFAULT_SCHED)
+
+/**
+ * By default, pthreads platforms use the <code>SCHED_OTHER</code> thread
+ * scheduling policy.
+ */
+
+#define HY_DEFAULT_SCHED SCHED_OTHER
+#endif
+
+#if !defined(HY_PRIORITY_MAP)
+
+/**
+ * If no priority map if provided, priorities will be determined
+ * algorithmically.
+ */
+
+#endif
+
+#if !defined(FALSE)
+#define FALSE ((BOOLEAN) 0)
+#if !defined(TRUE)
+#define TRUE ((BOOLEAN) (!FALSE))
+#endif
+#endif
+
+#if !defined(NULL)
+#if defined(__cplusplus)
+#define NULL (0)
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+#define USE_PROTOTYPES
+#if defined(USE_PROTOTYPES)
+#define PROTOTYPE(x) x
+#define VARARGS , ...
+#else
+#define PROTOTYPE(x) ()
+#define VARARGS
+#endif
+
+/**
+ * Assign the default line delimiter, if it was not set.
+ */
+
+#if !defined(PLATFORM_LINE_DELIMITER)
+#define PLATFORM_LINE_DELIMITER "\015\012"
+#endif
+
+/**
+ * Set the max path length, if it was not set.
+ */
+
+#if !defined(MAX_IMAGE_PATH_LENGTH)
+#define MAX_IMAGE_PATH_LENGTH (2048)
+#endif
+typedef double ESDOUBLE;
+typedef float ESSINGLE;
+
+/**
+ * Helpers for U_64s.
+ */
+
+#define CLEAR_U64(u64) (u64 = (U_64)0)
+#define LOW_LONG(l) (*((U_32 *) &(l)))
+#define HIGH_LONG(l) (*(((U_32 *) &(l)) + 1))
+#define I8(x) ((I_8) (x))
+#define I8P(x) ((I_8 *) (x))
+#define U16(x) ((U_16) (x))
+#define I16(x) ((I_16) (x))
+#define I16P(x) ((I_16 *) (x))
+#define U32(x) ((U_32) (x))
+#define I32(x) ((I_32) (x))
+#define I32P(x) ((I_32 *) (x))
+#define U16P(x) ((U_16 *) (x))
+#define U32P(x) ((U_32 *) (x))
+#define OBJP(x) ((HyObject *) (x))
+#define OBJPP(x) ((HyObject **) (x))
+#define OBJPPP(x) ((HyObject ***) (x))
+#define CLASSP(x) ((Class *) (x))
+#define CLASSPP(x) ((Class **) (x))
+#define BYTEP(x) ((BYTE *) (x))
+
+/**
+ * Test - was conflicting with OS2.h
+ */
+
+#define ESCHAR(x) ((CHARACTER) (x))
+#define FLT(x) ((FLOAT) x)
+#define FLTP(x) ((FLOAT *) (x))
+#if defined(NO_LVALUE_CASTING)
+#define LI8(x) (*((I_8 *) &(x)))
+#define LI8P(x) (*((I_8 **) &(x)))
+#define LU16(x) (*((U_16 *) &(x)))
+#define LI16(x) (*((I_16 *) &(x)))
+#define LU32(x) (*((U_32 *) &(x)))
+#define LI32(x) (*((I_32 *) &(x)))
+#define LI32P(x) (*((I_32 **) &(x)))
+#define LU16P(x) (*((U_16 **) &(x)))
+#define LU32P(x) (*((U_32 **) &(x)))
+#define LOBJP(x) (*((HyObject **) &(x)))
+#define LOBJPP(x) (*((HyObject ***) &(x)))
+#define LOBJPPP(x) (*((HyObject ****) &(x))
+#define LCLASSP(x) (*((Class **) &(x)))
+#define LBYTEP(x) (*((BYTE **) &(x)))
+#define LCHAR(x) (*((CHARACTER) &(x)))
+#define LFLT(x) (*((FLOAT) &x))
+#define LFLTP(x) (*((FLOAT *) &(x)))
+#else
+#define LI8(x) I8((x))
+#define LI8P(x) I8P((x))
+#define LU16(x) U16((x))
+#define LI16(x) I16((x))
+#define LU32(x) U32((x))
+#define LI32(x) I32((x))
+#define LI32P(x) I32P((x))
+#define LU16P(x) U16P((x))
+#define LU32P(x) U32P((x))
+#define LOBJP(x) OBJP((x))
+#define LOBJPP(x) OBJPP((x))
+#define LOBJPPP(x) OBJPPP((x))
+#define LIOBJP(x) IOBJP((x))
+#define LCLASSP(x) CLASSP((x))
+#define LBYTEP(x) BYTEP((x))
+#define LCHAR(x) CHAR((x))
+#define LFLT(x) FLT((x))
+#define LFLTP(x) FLTP((x))
+#endif
+
+/**
+ * Macros for converting between words and longs and accessing bits.
+ */
+
+#define HIGH_WORD(x) U16(U32((x)) >> 16)
+#define LOW_WORD(x) U16(U32((x)) & 0xFFFF)
+#define LOW_BIT(o) (U32((o)) & 1)
+#define LOW_2_BITS(o) (U32((o)) & 3)
+#define LOW_3_BITS(o) (U32((o)) & 7)
+#define LOW_4_BITS(o) (U32((o)) & 15)
+#define MAKE_32(h, l) ((U32((h)) << 16) | U32((l)))
+#define MAKE_64(h, l) ((((I_64)(h)) << 32) | (l))
+#if defined(__cplusplus)
+#define HY_CFUNC "C"
+#define HY_CDATA "C"
+#else
+#define HY_CFUNC
+#define HY_CDATA
+#endif
+
+/**
+ * Macros for tagging functions which read/write the vm thread.
+ */
+
+#define READSVMTHREAD
+#define WRITESVMTHREAD
+#define REQUIRESSTACKFRAME
+
+/**
+ * Macro for tagging functions, which never return.
+ */
+
+#if defined(__GNUC__)
+
+/**
+ * On GCC, we can actually pass this information on to the compiler.
+ */
+
+#define NORETURN __attribute__((noreturn))
+#else
+#define NORETURN
+#endif
+
+/**
+ * On some systems va_list is an array type. This is probably in
+ * violation of the ANSI C spec, but it's not entirely clear. Because of
+ * this, we end up with an undesired extra level of indirection if we take
+ * the address of a va_list argument.
+ *
+ * To get it right, always use the VA_PTR macro
+ */
+
+#if !defined(VA_PTR)
+#define VA_PTR(valist) (&valist)
+#endif
+#if !defined(TOC_UNWRAP_ADDRESS)
+#define TOC_UNWRAP_ADDRESS(wrappedPointer) (wrappedPointer)
+#endif
+
+#if !defined(TOC_STORE_TOC)
+#define TOC_STORE_TOC(dest,wrappedPointer)
+#endif
+/**
+ * Macros for accessing I_64 values.
+ */
+
+#if defined(ATOMIC_LONG_ACCESS)
+#define PTR_LONG_STORE(dstPtr, aLongPtr) ((*U32P(dstPtr) = *U32P(aLongPtr)), (*(U32P(dstPtr)+1) = *(U32P(aLongPtr)+1)))
+#define PTR_LONG_VALUE(dstPtr, aLongPtr) ((*U32P(aLongPtr) = *U32P(dstPtr)), (*(U32P(aLongPtr)+1) = *(U32P(dstPtr)+1)))
+#else
+#define PTR_LONG_STORE(dstPtr, aLongPtr) (*(dstPtr) = *(aLongPtr))
+#define PTR_LONG_VALUE(dstPtr, aLongPtr) (*(aLongPtr) = *(dstPtr))
+#endif
+
+/**
+ * Macro used when declaring tables which require relocations.
+ */
+
+#if !defined(HYCONST_TABLE)
+#define HYCONST_TABLE const
+#endif
+
+/**
+ * ANSI qsort is not always available.
+ */
+
+#if !defined(HY_SORT)
+#define HY_SORT(base, nmemb, size, compare) qsort((base), (nmemb), (size), (compare))
+#endif
+
+#endif /* hycomp_h */
diff --git a/luni/src/main/native/java_io_File.c b/luni/src/main/native/java_io_File.c
new file mode 100644
index 0000000..bf89681
--- /dev/null
+++ b/luni/src/main/native/java_io_File.c
@@ -0,0 +1,704 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define MaxPath 1024
+
+#include "JNIHelp.h"
+
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <utime.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <assert.h>
+
+
+/* these were copied from java.io.File */
+enum {
+ STAT_TYPE_EXISTS = 0x0001,
+ STAT_TYPE_DIR = 0x0002,
+ STAT_TYPE_FILE = 0x0004
+};
+
+static void convertToPlatform(char *path) {
+ char *pathIndex;
+
+ pathIndex = path;
+ while(*pathIndex != '\0') {
+ if(*pathIndex == '\\') {
+ *pathIndex = '/';
+ }
+ pathIndex++;
+ }
+}
+
+/*
+ * private static native byte[][] rootsImpl()
+ *
+ * Returns the linux root in an array of byte arrays
+ */
+static jobject java_io_File_rootsImpl(JNIEnv* env, jclass clazz) {
+ char rootStrings[3];
+ jarray answer;
+
+ rootStrings[0] = '/';
+ rootStrings[1] = '\0';
+ rootStrings[2] = '\0';
+
+ jclass arrayClass = (*env)->FindClass(env, "[B");
+ if (arrayClass == NULL)
+ return NULL;
+
+ answer = (*env)->NewObjectArray(env, 1, arrayClass, NULL);
+ if (!answer)
+ return NULL;
+
+ jbyteArray rootname;
+
+ rootname = (*env)->NewByteArray(env, 3);
+ (*env)->SetByteArrayRegion(env, rootname, 0, 3, (jbyte *) rootStrings);
+ (*env)->SetObjectArrayElement(env, answer, 0, rootname);
+ //(*env)->DeleteLocalRef(env, rootname);
+
+ return answer;
+}
+
+static jbyteArray java_io_File_getCanonImpl(JNIEnv * env, jobject recv,
+ jbyteArray path) {
+ /* This needs work. Currently it does no more or less than VAJ-20 ST
+ * implementationbut really should figure out '..', '.', and really
+ * resolve references.
+ */
+ jbyteArray answer;
+ size_t answerlen;
+ char *pathIndex;
+ char pathCopy[MaxPath];
+ jsize length = (jsize) (*env)->GetArrayLength(env, path);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+
+ convertToPlatform(pathCopy);
+
+ answerlen = strlen(pathCopy);
+ answer = (*env)->NewByteArray(env, answerlen);
+ (*env)->SetByteArrayRegion(env, answer, 0, answerlen, (jbyte *) pathCopy);
+
+ return answer;
+}
+
+/*
+ * native private boolean deleteFileImpl()
+ *
+ * Returns "true" if the file exists and was successfully deleted.
+ */
+static jboolean java_io_File_deleteFileImpl(JNIEnv* env, jobject obj,
+ jbyteArray path) {
+
+ int cc;
+
+ if(path == NULL) {
+ return JNI_FALSE; /* exception thrown */
+ }
+
+ char pathCopy[MaxPath];
+ jsize length = (jsize) (*env)->GetArrayLength(env, path);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ cc = unlink(pathCopy);
+ if(cc < 0) {
+ int err = errno;
+
+ /*
+ * According to the man pages, Linux uses EISDIR and Mac OS X
+ * uses EPERM to indicate a non-super-user attempt to unlink
+ * a directory. Mac OS does have EISDIR in the header file.
+ *
+ * We should get EACCES if the problem is directory permissions.
+ */
+ if(err == EISDIR || err == EPERM) {
+ cc = rmdir(pathCopy);
+ if(cc < 0) {
+ /* probably ENOTEMPTY */
+ LOGD("unable to rmdir '%s': %s (errno=%d)\n",
+ pathCopy, strerror(err), err);
+ }
+ } else {
+ LOGD("unable to unlink '%s': %s (errno=%d)\n",
+ pathCopy, strerror(err), err);
+ }
+ }
+
+ return (cc == 0);
+}
+
+/*
+ * harmony implements this method practically identical to the deleteFileImpl,
+ * except that it uses a diffrent helper method from hyport. Dalvik seems to
+ * just need this one method to delete both
+ */
+static jboolean java_io_File_deleteDirImpl(JNIEnv * env, jobject recv,
+ jbyteArray path) {
+ return java_io_File_deleteFileImpl( env, recv, path);
+}
+
+/*
+ * native public long lengthImpl()
+ *
+ * Returns the file length, or 0 if the file does not exist. The result for
+ * a directory is not defined.
+ */
+static jlong java_io_File_lengthImpl(JNIEnv* env, jobject obj,
+ jbyteArray path) {
+ struct stat sb;
+ jlong result = 0;
+ int cc;
+
+ char pathCopy[MaxPath];
+ jsize length = (jsize) (*env)->GetArrayLength(env, path);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ cc = stat(pathCopy, &sb);
+ if(cc == 0) {
+ // BEGIN android-added
+ /*
+ * This explicitly treats non-regular files (e.g., sockets and
+ * block-special devices) as having size zero. Some synthetic
+ * "regular" files may report an arbitrary non-zero size, but
+ * in these cases they generally report a block count of zero.
+ * So, use a zero block count to trump any other concept of
+ * size.
+ */
+ if (S_ISREG(sb.st_mode) && (sb.st_blocks != 0)) {
+ result = sb.st_size;
+ } else {
+ result = 0;
+ }
+ // END android-added
+ // BEGIN android-deleted
+ //result = sb.st_size;
+ // END android-deleted
+ }
+
+ return result;
+}
+
+/*
+ * native public long lastModified()
+ *
+ * Get the last modified date of the file. Measured in milliseconds
+ * from epoch (00:00:00 GMT, January 1, 1970). Returns 0 if the file does
+ * not exist
+ */
+static jlong java_io_File_lastModifiedImpl(JNIEnv* env, jobject obj,
+ jbyteArray path) {
+ struct stat sb;
+ jlong result = 0;
+ int cc;
+
+ char pathCopy[MaxPath];
+ jsize length = (jsize) (*env)->GetArrayLength(env, path);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ cc = stat(pathCopy, &sb);
+ if(cc == 0) {
+ // sb.st_mtime is a time_t which is in seconds since epoch.
+ result = sb.st_mtime;
+ result *= 1000L;
+ }
+
+ return result;
+}
+
+/*
+ * private static native int stattype(String path)
+ */
+static jint java_io_File_stattype(JNIEnv* env, jobject recv,
+ jbyteArray pathStr) {
+
+ char pathCopy[MaxPath];
+ jsize length = (jsize) (*env)->GetArrayLength(env, pathStr);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, pathStr, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ struct stat sb;
+ int cc, type;
+
+ type = 0;
+ cc = stat(pathCopy, &sb);
+
+ if(cc == 0) {
+ type |= STAT_TYPE_EXISTS;
+ if(S_ISDIR(sb.st_mode)) {
+ type |= STAT_TYPE_DIR;
+ } else if(S_ISREG(sb.st_mode)) {
+ type |= STAT_TYPE_FILE;
+ }
+ }
+
+ return type;
+}
+
+static jboolean java_io_File_isDirectoryImpl(JNIEnv* env, jobject recv,
+ jbyteArray pathStr) {
+ return ((java_io_File_stattype(env, recv, pathStr) & STAT_TYPE_DIR)
+ == STAT_TYPE_DIR);
+}
+
+static jboolean java_io_File_existsImpl(JNIEnv* env, jobject recv,
+ jbyteArray pathStr) {
+ return ((java_io_File_stattype(env, recv, pathStr) & STAT_TYPE_EXISTS)
+ == STAT_TYPE_EXISTS);
+}
+
+static jboolean java_io_File_isFileImpl(JNIEnv* env, jobject recv,
+ jbyteArray pathStr) {
+ return ((java_io_File_stattype(env, recv, pathStr) & STAT_TYPE_FILE)
+ == STAT_TYPE_FILE);
+}
+
+static jboolean java_io_File_isHiddenImpl(JNIEnv * env, jobject recv,
+ jbyteArray path) {
+
+ char pathCopy[MaxPath];
+ jsize index;
+ jsize length = (*env)->GetArrayLength(env, path);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+
+ if(length == 0) {
+ return 0;
+ }
+
+ ((*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy));
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ if(!java_io_File_existsImpl(env, recv, path)) {
+ return 0;
+ }
+
+ for(index = length; index >= 0; index--) {
+ if(pathCopy[index] == '.'
+ && (index > 0 && pathCopy[index - 1] == '/')) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static jboolean java_io_File_readable(JNIEnv* env, jobject recv,
+ jbyteArray pathStr) {
+ char path[MaxPath];
+ struct stat sb;
+ int cc, type;
+
+ if(pathStr == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return -1;
+ }
+
+ jsize length = (jsize) (*env)->GetArrayLength(env, pathStr);
+
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, pathStr, 0, length, (jbyte *)path);
+ path[length] = '\0';
+ convertToPlatform(path);
+
+ cc = access(path, R_OK);
+
+ return cc == 0;
+}
+
+static jboolean java_io_File_writable(JNIEnv* env, jobject recv,
+ jbyteArray pathStr) {
+ char path[MaxPath];
+ struct stat sb;
+ int cc, type;
+
+ if(pathStr == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return -1;
+ }
+
+ jsize length = (jsize) (*env)->GetArrayLength(env, pathStr);
+
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, pathStr, 0, length, (jbyte *)path);
+ path[length] = '\0';
+ convertToPlatform(path);
+
+ cc = access(path, W_OK);
+
+ return cc == 0;
+}
+
+// BEGIN android-deleted
+#if 0
+static jboolean java_io_File_isReadOnlyImpl(JNIEnv* env, jobject recv,
+ jbyteArray path) {
+
+ return (java_io_File_readable(env, recv, path)
+ && !java_io_File_writable(env, recv, path));
+}
+
+static jboolean java_io_File_isWriteOnlyImpl(JNIEnv* env, jobject recv,
+ jbyteArray path) {
+
+ return (!java_io_File_readable(env, recv, path)
+ && java_io_File_writable(env, recv, path));
+}
+#endif
+// END android-deleted
+
+static jbyteArray java_io_File_getLinkImpl(JNIEnv* env, jobject recv,
+ jbyteArray path) {
+ jbyteArray answer;
+ jsize answerlen;
+ char pathCopy[MaxPath];
+
+ jsize length = (jsize) (*env)->GetArrayLength(env, path);
+
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ jboolean test = -1;
+
+ char *link = pathCopy;
+
+ int size = readlink(link, link, MaxPath);
+ if(size <= 0) {
+ test = 0;
+ } else {
+ if(size >= MaxPath) {
+ link[MaxPath - 1] = 0;
+ } else {
+ link[size] = 0;
+ }
+ }
+
+ if(test) {
+ answerlen = strlen(pathCopy);
+ answer = (*env)->NewByteArray(env, answerlen);
+ (*env)->SetByteArrayRegion(env, answer, 0, answerlen,
+ (jbyte *) pathCopy);
+ } else {
+ answer = path;
+ }
+
+ return answer;
+}
+
+static jboolean java_io_File_setLastModifiedImpl(JNIEnv* env, jobject recv,
+ jbyteArray path, jlong time) {
+ jboolean result;
+
+ jsize length = (*env)->GetArrayLength(env, path);
+ char pathCopy[MaxPath];
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ ((*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy));
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ struct stat statbuf;
+ struct utimbuf timebuf;
+ if(stat(pathCopy, &statbuf)) {
+ result = 0;
+ } else {
+ timebuf.actime = statbuf.st_atime;
+ timebuf.modtime = (time_t) (time / 1000);
+ result = utime(pathCopy, &timebuf) == 0;
+ }
+
+ return result;
+}
+
+static jboolean java_io_File_setReadOnlyImpl(JNIEnv* env, jobject recv,
+ jbyteArray path) {
+ jsize length = (*env)->GetArrayLength(env, path);
+ char pathCopy[MaxPath];
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+
+ ((*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy));
+
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ struct stat buffer;
+ mode_t mode;
+ if(stat(pathCopy, &buffer)) {
+ return 0;
+ }
+ mode = buffer.st_mode;
+ mode = mode & 07555;
+
+ return chmod(pathCopy, mode) == 0;
+}
+
+static jobject java_io_File_listImpl(JNIEnv* env, jclass clazz,
+ jbyteArray path) {
+
+ struct dirEntry {
+ char pathEntry[MaxPath];
+ struct dirEntry *next;
+ } *dirList, *currentEntry;
+
+ jsize length = (*env)->GetArrayLength(env, path);
+ char pathCopy[MaxPath];
+ char filename[MaxPath];
+ jint result = 0, index;
+ jint numEntries = 0;
+ jarray answer = NULL;
+ jclass javaClass = NULL;
+
+ dirList = NULL;
+ currentEntry = NULL;
+
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ ((*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy));
+ if(length >= 1 && pathCopy[length - 1] != '\\'
+ && pathCopy[length - 1] != '/') {
+ pathCopy[length] = '/';
+ length++;
+ }
+ pathCopy[length] = '\0';
+
+ convertToPlatform(pathCopy);
+
+ DIR *dirp = NULL;
+ struct dirent *entry;
+
+ dirp = opendir(pathCopy);
+
+ if(dirp == NULL) {
+ return NULL;
+ }
+
+ entry = readdir(dirp);
+
+ if(entry == NULL) {
+ closedir(dirp);
+ return NULL;
+ }
+ strcpy(filename, entry->d_name);
+
+ while(result > -1) {
+ if(strcmp(".", filename) != 0 && (strcmp("..", filename) != 0)) {
+ if(numEntries > 0) {
+ currentEntry->next =
+ (struct dirEntry *) malloc(sizeof(struct dirEntry));
+ currentEntry = currentEntry->next;
+ } else {
+ dirList = (struct dirEntry *) malloc(sizeof(struct dirEntry));
+ currentEntry = dirList;
+ }
+ if(currentEntry == NULL) {
+ closedir(dirp);
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ goto cleanup;
+ }
+ strcpy(currentEntry->pathEntry, filename);
+ numEntries++;
+ }
+
+ entry = readdir(dirp);
+
+ if(entry == NULL) {
+ result = -1;
+ } else {
+ strcpy(filename, entry->d_name);
+ }
+ }
+ closedir(dirp);
+
+ if(numEntries == 0) {
+ return NULL;
+ }
+
+ javaClass = (*env)->FindClass(env, "[B");
+ if(javaClass == NULL) {
+ return NULL;
+ }
+ answer = (*env)->NewObjectArray(env, numEntries, javaClass, NULL);
+
+cleanup:
+ for(index = 0; index < numEntries; index++)
+ {
+ jbyteArray entrypath;
+ jsize entrylen = strlen(dirList->pathEntry);
+ currentEntry = dirList;
+ if(answer)
+ {
+ entrypath = (*env)->NewByteArray(env, entrylen);
+ (*env)->SetByteArrayRegion(env, entrypath, 0, entrylen,
+ (jbyte *) dirList->pathEntry);
+ (*env)->SetObjectArrayElement(env, answer, index, entrypath);
+ (*env)->DeleteLocalRef(env, entrypath);
+ }
+ dirList = dirList->next;
+ free((void *)currentEntry);
+ }
+
+ return answer;
+}
+
+static jboolean java_io_File_mkdirImpl(JNIEnv* env, jobject recv,
+ jbyteArray path) {
+ jint result;
+ char pathCopy[MaxPath];
+ jsize length = (*env)->GetArrayLength(env, path);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ ((*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy));
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+// BEGIN android-changed
+// don't want default permissions to allow global access.
+ result = mkdir(pathCopy, S_IRWXU);
+// END android-changed
+
+ if(-1 != result)
+ {
+ result = 0;
+ }
+
+ return result == 0;
+}
+
+static jint java_io_File_newFileImpl(JNIEnv* env, jobject recv,
+ jbyteArray path) {
+
+ if(path == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return -1;
+ }
+
+ jint result;
+ jsize length = (*env)->GetArrayLength(env, path);
+ char pathCopy[MaxPath];
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ (*env)->GetByteArrayRegion(env, path, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+ convertToPlatform(pathCopy);
+
+ /* First check to see if file already exists */
+ if(java_io_File_existsImpl(env, recv, path))
+ {
+ return 1;
+ }
+
+ /* Now create the file and close it */
+// BEGIN android-changed
+// don't want default permissions to allow global access.
+ int fd = open(pathCopy, O_EXCL | O_CREAT, 0600);
+// END android-changed
+ if(fd == -1)
+ {
+ if(errno == EEXIST) {
+ return 1;
+ }
+ return -1;
+ }
+ close(fd);
+
+ return 0;
+}
+
+static jboolean java_io_File_renameToImpl(JNIEnv* env, jobject recv,
+ jbyteArray pathExist, jbyteArray pathNew) {
+ jint result;
+ jsize length;
+ char pathExistCopy[MaxPath], pathNewCopy[MaxPath];
+
+ length = (*env)->GetArrayLength(env, pathExist);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ ((*env)->GetByteArrayRegion(env, pathExist, 0, length,
+ (jbyte *)pathExistCopy));
+ pathExistCopy[length] = '\0';
+
+ length = (*env)->GetArrayLength(env, pathNew);
+ length = length < MaxPath - 1 ? length : MaxPath - 1;
+ ((*env)->GetByteArrayRegion(env, pathNew, 0, length,
+ (jbyte *)pathNewCopy));
+ pathNewCopy[length] = '\0';
+
+ convertToPlatform(pathExistCopy);
+ convertToPlatform(pathNewCopy);
+
+ result = rename(pathExistCopy, pathNewCopy);
+
+ return result == 0;
+}
+
+static void java_io_File_oneTimeInitialization(JNIEnv * env, jclass clazz)
+{
+ // dummy to stay compatible to harmony
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "rootsImpl", "()[[B", (void*) java_io_File_rootsImpl },
+ { "deleteDirImpl", "([B)Z", (void*) java_io_File_deleteDirImpl },
+ { "deleteFileImpl", "([B)Z", (void*) java_io_File_deleteFileImpl },
+ { "existsImpl", "([B)Z", (void*) java_io_File_existsImpl },
+ { "getCanonImpl", "([B)[B", (void*) java_io_File_getCanonImpl },
+ { "isDirectoryImpl", "([B)Z", (void*) java_io_File_isDirectoryImpl },
+ { "isFileImpl", "([B)Z", (void*) java_io_File_isFileImpl },
+ { "isHiddenImpl", "([B)Z", (void*) java_io_File_isHiddenImpl },
+ // BEGIN android-changed
+ { "isReadableImpl", "([B)Z", (void*) java_io_File_readable },
+ { "isWriteableImpl", "([B)Z", (void*) java_io_File_writable },
+ // END android-changed
+ { "getLinkImpl", "([B)[B", (void*) java_io_File_getLinkImpl },
+ { "lastModifiedImpl", "([B)J", (void*) java_io_File_lastModifiedImpl },
+ { "setReadOnlyImpl", "([B)Z", (void*) java_io_File_setReadOnlyImpl },
+ { "lengthImpl", "([B)J", (void*) java_io_File_lengthImpl },
+ { "listImpl", "([B)[[B",(void*) java_io_File_listImpl },
+ { "mkdirImpl", "([B)Z", (void*) java_io_File_mkdirImpl },
+ { "newFileImpl", "([B)I", (void*) java_io_File_newFileImpl },
+ { "renameToImpl", "([B[B)Z",(void*) java_io_File_renameToImpl },
+ { "setLastModifiedImpl","([BJ)Z",
+ (void*) java_io_File_setLastModifiedImpl },
+ { "oneTimeInitialization","()V",
+ (void*) java_io_File_oneTimeInitialization }
+};
+int register_java_io_File(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/io/File",
+ gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/java_io_FileDescriptor.c b/luni/src/main/native/java_io_FileDescriptor.c
new file mode 100644
index 0000000..a5ec8b7
--- /dev/null
+++ b/luni/src/main/native/java_io_FileDescriptor.c
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+
+/*
+ * These are JNI field IDs for the stuff we're interested in. They're
+ * computed when the class is loaded.
+ */
+static struct {
+ jfieldID descriptor; /* int */
+ jmethodID constructorInt;
+ jmethodID setFD;
+ jclass clazz;
+} gCachedFields;
+
+/*
+ * Internal helper function.
+ *
+ * Get the file descriptor.
+ */
+static inline int getFd(JNIEnv* env, jobject obj)
+{
+ return (*env)->GetIntField(env, obj, gCachedFields.descriptor);
+}
+
+/*
+ * Internal helper function.
+ *
+ * Set the file descriptor.
+ */
+static inline void setFd(JNIEnv* env, jobject obj, jint value)
+{
+ (*env)->SetIntField(env, obj, gCachedFields.descriptor, value);
+}
+
+/*
+ * native private static void nativeClassInit()
+ *
+ * Perform one-time initialization. If the class is unloaded and re-loaded,
+ * this will be called again.
+ */
+static void nativeClassInit(JNIEnv* env, jclass clazz)
+{
+ gCachedFields.clazz = (*env)->NewGlobalRef(env, clazz);
+
+ gCachedFields.descriptor =
+ (*env)->GetFieldID(env, clazz, "descriptor", "I");
+
+ if(gCachedFields.descriptor == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError", "FileDescriptor");
+ return;
+ }
+
+ gCachedFields.constructorInt =
+ (*env)->GetMethodID(env, clazz, "<init>", "()V");
+
+ if(gCachedFields.constructorInt == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "<init>()V");
+ return;
+ }
+}
+
+/*
+ * public native void sync()
+ */
+static void fd_sync(JNIEnv* env, jobject obj) {
+ int fd = getFd(env, obj);
+
+ if (fsync(fd) != 0) {
+ /*
+ * If fd is a socket, then fsync(fd) is defined to fail with
+ * errno EINVAL. This isn't actually cause for concern.
+ * TODO: Look into not bothering to call fsync() at all if
+ * we know we are dealing with a socket.
+ */
+ if (errno != EINVAL) {
+ jniThrowException(env, "java/io/SyncFailedException", "");
+ }
+ }
+}
+
+/*
+ * public native boolean valid()
+ */
+static jboolean fd_valid(JNIEnv* env, jobject obj) {
+ int fd = getFd(env, obj);
+ struct stat sb;
+
+ if(fstat(fd, &sb) == 0) {
+ return JNI_TRUE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+/* checks to see if class is inited and inits if needed, returning -1
+ * on fail and 0 on success
+ */
+static int checkClassInit (JNIEnv *env) {
+ if(gCachedFields.clazz == NULL) {
+ /* this should cause the class to be inited and
+ * our static variables to be filled in
+ *
+ * (Note that FindClass just loads the class; it doesn't get
+ * initialized until we try to do something with it.)
+ */
+ jclass clazz;
+ clazz = (*env)->FindClass(env, "java/io/FileDescriptor");
+ if(clazz == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.io.FileDescriptor");
+ return -1;
+ }
+
+ jfieldID readWriteId;
+ readWriteId = (*env)->GetStaticFieldID(env, clazz, "in",
+ "Ljava/io/FileDescriptor;");
+ if(readWriteId == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldException",
+ "FileDescriptor.readOnly(Z)");
+ return -1;
+ }
+
+ (void) (*env)->GetStaticObjectField(env, clazz, readWriteId);
+ }
+
+ return 0;
+}
+
+
+/*
+ * For JNIHelp.c
+ * Create a java.io.FileDescriptor given an integer fd
+ */
+
+jobject jniCreateFileDescriptor (JNIEnv *env, int fd) {
+ jobject ret;
+
+ /* the class may not have been loaded yet */
+ if(checkClassInit(env) < 0) {
+ return NULL;
+ }
+
+ ret = (*env)->NewObject(env, gCachedFields.clazz,
+ gCachedFields.constructorInt);
+
+ (*env)->SetIntField(env, ret, gCachedFields.descriptor, fd);
+
+ return ret;
+}
+
+/*
+ * For JNIHelp.c
+ * Get an int file descriptor from a java.io.FileDescriptor
+ */
+
+int jniGetFDFromFileDescriptor (JNIEnv* env, jobject fileDescriptor) {
+ /* should already be initialized if it's an actual FileDescriptor */
+ assert(fileDescriptor != NULL);
+ assert(gCachedFields.clazz != NULL);
+
+ return getFd(env, fileDescriptor);
+}
+
+/*
+ * For JNIHelp.c
+ * Set the descriptor of a java.io.FileDescriptor
+ */
+
+void jniSetFileDescriptorOfFD (JNIEnv* env, jobject fileDescriptor, int value) {
+ /* should already be initialized if it's an actual FileDescriptor */
+ assert(fileDescriptor != NULL);
+ assert(gCachedFields.clazz != NULL);
+
+ setFd(env, fileDescriptor, value);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "oneTimeInitialization", "()V", nativeClassInit },
+ { "syncImpl", "()V", fd_sync },
+ { "valid", "()Z", fd_valid }
+};
+int register_java_io_FileDescriptor(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "java/io/FileDescriptor",
+ gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/java_io_ObjectInputStream.c b/luni/src/main/native/java_io_ObjectInputStream.c
new file mode 100644
index 0000000..3519055
--- /dev/null
+++ b/luni/src/main/native/java_io_ObjectInputStream.c
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+
+static void java_setFieldBool (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jboolean newValue) {
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "Z");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetBooleanField(env, targetObject, fid, newValue);
+ }
+}
+
+static void java_setFieldChar (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jchar newValue) {
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "C");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetCharField(env, targetObject, fid, newValue);
+ }
+}
+
+static void java_setFieldInt (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jint newValue) {
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "I");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetIntField(env, targetObject, fid, newValue);
+ }
+}
+
+static void java_setFieldFloat (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jfloat newValue) {
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "F");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetFloatField(env, targetObject, fid, newValue);
+ }
+}
+
+static void java_setFieldDouble (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jdouble newValue) {
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "D");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetDoubleField(env, targetObject, fid, newValue);
+ }
+
+}
+
+static void java_setFieldShort (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jshort newValue) {
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "S");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetShortField(env, targetObject, fid, newValue);
+ }
+
+}
+
+static void java_setFieldLong (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jlong newValue) {
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "J");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetLongField(env, targetObject, fid, newValue);
+ }
+}
+
+static jobject java_newInstance (JNIEnv * env, jclass clazz,
+ jclass instantiationClass,
+ jclass constructorClass) {
+ jmethodID mid =
+ (*env)->GetMethodID(env, constructorClass, "<init>", "()V");
+
+ if(mid == 0) {
+ /* Cant newInstance,No empty constructor... */
+ return (jobject) 0;
+ } else {
+ /* Instantiate an object of a given class */
+ return (jobject) (*env)->NewObject(env, instantiationClass, mid);
+ }
+
+}
+
+static void java_setFieldByte (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jbyte newValue){
+ const char *fieldNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "B");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /* Two options now. Maybe getFieldID caused an exception, or maybe it returned the real value */
+ if(fid != 0) {
+ (*env)->SetByteField(env, targetObject, fid, newValue);
+ }
+}
+
+static void java_setFieldObj (JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jstring fieldTypeName,
+ jobject newValue) {
+ const char *fieldNameInC, *fieldTypeNameInC;
+ jfieldID fid;
+ if(targetObject == NULL) {
+ return;
+ }
+ fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ fieldTypeNameInC = (*env)->GetStringUTFChars(env, fieldTypeName, NULL);
+ fid = (*env)->GetFieldID(env, declaringClass,
+ fieldNameInC, fieldTypeNameInC);
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+ (*env)->ReleaseStringUTFChars(env, fieldTypeName, fieldTypeNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid != 0) {
+ (*env)->SetObjectField(env, targetObject, fid, newValue);
+ }
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;J)V",
+ (void*) java_setFieldLong },
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;S)V",
+ (void*) java_setFieldShort },
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;D)V",
+ (void*) java_setFieldDouble },
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Z)V",
+ (void*) java_setFieldBool },
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;B)V",
+ (void*) java_setFieldByte },
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;F)V",
+ (void*) java_setFieldFloat },
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;C)V",
+ (void*) java_setFieldChar },
+ { "setField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;I)V",
+ (void*) java_setFieldInt },
+ { "newInstance",
+ "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Object;",
+ (void*) java_newInstance },
+ { "objSetField",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V",
+ (void*) java_setFieldObj }
+
+};
+int register_java_io_ObjectInputStream(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "java/io/ObjectInputStream",
+ gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/java_io_ObjectOutputStream.c b/luni/src/main/native/java_io_ObjectOutputStream.c
new file mode 100644
index 0000000..e465bc2
--- /dev/null
+++ b/luni/src/main/native/java_io_ObjectOutputStream.c
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+
+static jlong java_getFieldLong(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "J");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jlong) 0L;
+ } else {
+ return (*env)->GetLongField (env, targetObject, fid);
+ }
+}
+
+static jshort java_getFieldShort(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "S");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jshort) 0;
+ } else {
+ return (*env)->GetShortField (env, targetObject, fid);
+ }
+}
+
+static jdouble java_getFieldDouble(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "D");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jdouble) 0.0;
+ } else {
+ return (*env)->GetDoubleField (env, targetObject, fid);
+ }
+}
+
+static jboolean java_getFieldBool(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "Z");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jboolean) 0;
+ } else {
+ return (*env)->GetBooleanField (env, targetObject, fid);
+ }
+}
+
+static jbyte java_getFieldByte(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "B");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jbyte) 0;
+ } else {
+ return (*env)->GetByteField (env, targetObject, fid);
+ }
+}
+
+static jfloat java_getFieldFloat(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "F");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jfloat) 0.0f;
+ }
+ else {
+ return (*env)->GetFloatField (env, targetObject, fid);
+ }
+
+}
+
+static jchar java_getFieldChar(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "C");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jchar) 0;
+ } else {
+ return (*env)->GetCharField(env, targetObject, fid);
+ }
+}
+
+static jobject java_getFieldObj(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName,
+ jstring fieldTypeName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ const char *fieldTypeNameInC =
+ (*env)->GetStringUTFChars(env, fieldTypeName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass,
+ fieldNameInC, fieldTypeNameInC);
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+ (*env)->ReleaseStringUTFChars(env, fieldTypeName, fieldTypeNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused an exception,
+ * or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jobject) 0;
+ } else {
+ return (*env)->GetObjectField (env, targetObject, fid);
+ }
+}
+
+static jint java_getFieldInt(JNIEnv * env, jclass clazz,
+ jobject targetObject,
+ jclass declaringClass,
+ jstring fieldName) {
+ const char *fieldNameInC = (*env)->GetStringUTFChars(env, fieldName, NULL);
+ jfieldID fid = (*env)->GetFieldID(env, declaringClass, fieldNameInC, "I");
+ (*env)->ReleaseStringUTFChars(env, fieldName, fieldNameInC);
+
+ /*
+ * Two options now. Maybe getFieldID caused
+ * an exception, or maybe it returned the real value
+ */
+ if(fid == 0) {
+ // Field not found. I believe we must throw an exception here
+ return (jint) 0;
+ } else {
+ return (*env)->GetIntField(env, targetObject, fid);
+ }
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "getFieldLong",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)J",
+ (void*) java_getFieldLong },
+ { "getFieldShort",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)S",
+ (void*) java_getFieldShort },
+ { "getFieldDouble",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)D",
+ (void*) java_getFieldDouble },
+ { "getFieldBool",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)Z",
+ (void*) java_getFieldBool },
+ { "getFieldByte",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)B",
+ (void*) java_getFieldByte },
+ { "getFieldFloat",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)F",
+ (void*) java_getFieldFloat },
+ { "getFieldChar",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)C",
+ (void*) java_getFieldChar },
+ { "getFieldObj",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;",
+ (void*) java_getFieldObj },
+ { "getFieldInt",
+ "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/String;)I",
+ (void*) java_getFieldInt },
+
+};
+int register_java_io_ObjectOutputStream(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "java/io/ObjectOutputStream",
+ gMethods, NELEM(gMethods));
+}
+
diff --git a/luni/src/main/native/java_io_ObjectStreamClass.c b/luni/src/main/native/java_io_ObjectStreamClass.c
new file mode 100644
index 0000000..c3fb518
--- /dev/null
+++ b/luni/src/main/native/java_io_ObjectStreamClass.c
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+
+static jobject java_io_osc_getFieldSignature(JNIEnv * env, jclass clazz,
+ jobject reflectField) {
+ jclass lookupClass;
+ jmethodID mid;
+
+ lookupClass = (*env)->FindClass(env, "java/lang/reflect/Field");
+ if(!lookupClass) {
+ return NULL;
+ }
+
+ mid = (*env)->GetMethodID(env, lookupClass, "getSignature",
+ "()Ljava/lang/String;");
+ if(!mid)
+ {
+ return NULL;
+ }
+
+ jclass fieldClass = (*env)->GetObjectClass(env, reflectField);
+
+ return (*env)->CallNonvirtualObjectMethod(env, reflectField,
+ fieldClass, mid);
+}
+
+static jobject java_io_osc_getMethodSignature(JNIEnv * env, jclass clazz,
+ jobject reflectMethod)
+{
+ jclass lookupClass;
+ jmethodID mid;
+
+ lookupClass = (*env)->FindClass(env, "java/lang/reflect/Method");
+ if(!lookupClass) {
+ return NULL;
+ }
+
+ mid = (*env)->GetMethodID(env, lookupClass, "getSignature",
+ "()Ljava/lang/String;");
+ if(!mid) {
+ return NULL;
+ }
+
+ jclass methodClass = (*env)->GetObjectClass(env, reflectMethod);
+ return (*env)->CallNonvirtualObjectMethod(env, reflectMethod,
+ methodClass, mid);
+}
+
+static jobject java_io_osc_getConstructorSignature(JNIEnv * env,
+ jclass clazz,
+ jobject
+ reflectConstructor)
+{
+ jclass lookupClass;
+ jmethodID mid;
+
+ lookupClass = (*env)->FindClass(env, "java/lang/reflect/Constructor");
+ if(!lookupClass) {
+ return NULL;
+ }
+
+ mid = (*env)->GetMethodID(env, lookupClass, "getSignature",
+ "()Ljava/lang/String;");
+ if(!mid) {
+ return NULL;
+ }
+
+ jclass constructorClass = (*env)->GetObjectClass(env, reflectConstructor);
+ return (*env)->CallNonvirtualObjectMethod(env, reflectConstructor,
+ constructorClass, mid);
+}
+
+static jboolean java_io_osc_hasClinit(JNIEnv * env, jclass clazz,
+ jobject targetClass) {
+ jmethodID mid = (*env)->GetStaticMethodID(env, targetClass,
+ "<clinit>", "()V");
+ (*env)->ExceptionClear(env);
+
+ /*
+ * Can I just return mid and rely on typecast to convert to jboolean ?
+ * Safe implementation for now
+ */
+ if(mid == 0) {
+ /* No <clinit>... */
+ return (jboolean) 0;
+ } else {
+ return (jboolean) 1;
+ }
+}
+
+static void java_io_osc_oneTimeInitialization(JNIEnv * env, jclass clazz) {
+ // dummy to stay compatible to harmony
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "getFieldSignature",
+ "(Ljava/lang/reflect/Field;)Ljava/lang/String;",
+ (void*) java_io_osc_getFieldSignature },
+ { "getMethodSignature",
+ "(Ljava/lang/reflect/Method;)Ljava/lang/String;",
+ (void*) java_io_osc_getMethodSignature },
+ { "getConstructorSignature",
+ "(Ljava/lang/reflect/Constructor;)Ljava/lang/String;",
+ (void*) java_io_osc_getConstructorSignature },
+ { "hasClinit", "(Ljava/lang/Class;)Z",
+ (void*) java_io_osc_hasClinit },
+ { "oneTimeInitialization", "()V",
+ (void*) java_io_osc_oneTimeInitialization }
+};
+int register_java_io_ObjectStreamClass(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "java/io/ObjectStreamClass",
+ gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/java_lang_Character.cpp b/luni/src/main/native/java_lang_Character.cpp
new file mode 100644
index 0000000..c1324d6
--- /dev/null
+++ b/luni/src/main/native/java_lang_Character.cpp
@@ -0,0 +1,75 @@
+//
+// java_lang_Character.cpp
+// Android
+//
+// Copyright 2006 The Android Open Source Project
+//
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+
+//#define LOG_TAG "Character"
+//#include "utils/Log.h"
+#include "utils/AndroidUnicode.h"
+
+#include <stdlib.h>
+
+
+using namespace android;
+
+/*
+ * native private static int nativeGetData(int c)
+ */
+static jint getData(JNIEnv* env, jclass clazz, jint val)
+{
+ return Unicode::getPackedData(val);
+}
+
+/*
+ * native private static int nativeToLower(int c)
+ */
+static jint toLower(JNIEnv* env, jclass clazz, jint val)
+{
+ return Unicode::toLower(val);
+}
+
+/*
+ * native private static int nativeToUpper(int c)
+ */
+static jint toUpper(JNIEnv* env, jclass clazz, jint val)
+{
+ return Unicode::toUpper(val);
+}
+
+/*
+ * native private static int nativeNumericValue(int c)
+ */
+static jint numericValue(JNIEnv* env, jclass clazz, jint val)
+{
+ return Unicode::getNumericValue(val);
+}
+
+/*
+ * native private static int nativeToTitle(int c)
+ */
+static jint toTitle(JNIEnv* env, jclass clazz, jint val)
+{
+ return Unicode::toTitle(val);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeGetData", "(I)I", (void*) getData },
+ { "nativeToLower", "(I)I", (void*) toLower },
+ { "nativeToUpper", "(I)I", (void*) toUpper },
+ { "nativeNumericValue", "(I)I", (void*) numericValue },
+ { "nativeToTitle", "(I)I", (void*) toTitle },
+};
+int register_java_lang_Character(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/lang/Character",
+ gMethods, NELEM(gMethods));
+}
+
diff --git a/luni/src/main/native/java_lang_Double.c b/luni/src/main/native/java_lang_Double.c
new file mode 100644
index 0000000..fd4b7f1
--- /dev/null
+++ b/luni/src/main/native/java_lang_Double.c
@@ -0,0 +1,77 @@
+//
+// java_lang_Double.c
+// Android
+//
+// Copyright 2005 The Android Open Source Project
+//
+#include "JNIHelp.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+typedef union {
+ uint64_t bits;
+ double d;
+} Double;
+
+#define NaN (0x7ff8000000000000ULL)
+
+/*
+ * public static native long doubleToLongBits(double value)
+ */
+static jlong doubleToLongBits(JNIEnv* env, jclass clazz, jdouble val)
+{
+ Double d;
+
+ d.d = val;
+
+ // For this method all values in the NaN range are
+ // normalized to the canonical NaN value.
+
+ if (isnan(d.d))
+ d.bits = NaN;
+
+ return d.bits;
+}
+
+/*
+ * public static native long doubleToRawLongBits(double value)
+ */
+static jlong doubleToRawLongBits(JNIEnv* env, jclass clazz, jdouble val)
+{
+ Double d;
+
+ d.d = val;
+
+ return d.bits;
+}
+
+/*
+ * public static native double longBitsToDouble(long bits)
+ */
+static jdouble longBitsToDouble(JNIEnv* env, jclass clazz, jlong val)
+{
+ Double d;
+
+ d.bits = val;
+
+ return d.d;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "doubleToLongBits", "(D)J", doubleToLongBits },
+ { "doubleToRawLongBits", "(D)J", doubleToRawLongBits },
+ { "longBitsToDouble", "(J)D", longBitsToDouble },
+};
+int register_java_lang_Double(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/lang/Double",
+ gMethods, NELEM(gMethods));
+}
+
diff --git a/luni/src/main/native/java_lang_Float.c b/luni/src/main/native/java_lang_Float.c
new file mode 100644
index 0000000..2a7af21
--- /dev/null
+++ b/luni/src/main/native/java_lang_Float.c
@@ -0,0 +1,85 @@
+//
+// java_lang_Float.c
+// Android
+//
+// Copyright 2005 The Android Open Source Project
+//
+#include "JNIHelp.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef union {
+ unsigned int bits;
+ float f;
+} Float;
+
+#define NaN (0x7fc00000)
+
+/*
+ * Local helper function.
+ */
+static int IsNaN(unsigned bits)
+{
+ return ((bits >= 0x7f800001U && bits <= 0x7fffffffU)
+ || (bits >= 0xff800001U && bits <= 0xffffffffU));
+}
+
+/*
+ * public static native int floatToIntBits(float value)
+ */
+static jint floatToIntBits(JNIEnv* env, jclass clazz, jfloat val)
+{
+ Float f;
+
+ f.f = val;
+
+ // For this method all values in the NaN range are
+ // normalized to the canonical NaN value.
+
+ if (IsNaN(f.bits))
+ f.bits = NaN;
+
+ return f.bits;
+}
+
+/*
+ * public static native int floatToRawBits(float value)
+ */
+static jint floatToRawBits(JNIEnv* env, jclass clazz, jfloat val)
+{
+ Float f;
+
+ f.f = val;
+
+ return f.bits;
+}
+
+/*
+ * public static native float intBitsToFloat(int bits)
+ */
+static jfloat intBitsToFloat(JNIEnv* env, jclass clazz, jint val)
+{
+ Float f;
+
+ f.bits = val;
+
+ return f.f;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "floatToIntBits", "(F)I", floatToIntBits },
+ { "floatToRawIntBits", "(F)I", floatToRawBits },
+ { "intBitsToFloat", "(I)F", intBitsToFloat },
+};
+int register_java_lang_Float(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/lang/Float",
+ gMethods, NELEM(gMethods));
+}
+
diff --git a/luni/src/main/native/java_lang_Math.c b/luni/src/main/native/java_lang_Math.c
new file mode 100644
index 0000000..a3a69dd
--- /dev/null
+++ b/luni/src/main/native/java_lang_Math.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Native functions for java.lang.Math.
+ */
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+/* native public static double sin(double a); */
+static jdouble jsin(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return sin(a);
+}
+
+/* native public static double cos(double a); */
+static jdouble jcos(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return cos(a);
+}
+
+/* native public static double tan(double a); */
+static jdouble jtan(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return tan(a);
+}
+
+/* native public static double asin(double a); */
+static jdouble jasin(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return asin(a);
+}
+
+/* native public static double acos(double a); */
+static jdouble jacos(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return acos(a);
+}
+
+/* native public static double atan(double a); */
+static jdouble jatan(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return atan(a);
+}
+
+/* native public static double exp(double a); */
+static jdouble jexp(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return exp(a);
+}
+
+/* native public static double log(double a); */
+static jdouble jlog(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return log(a);
+}
+
+/* native public static double sqrt(double a); */
+static jdouble jsqrt(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return sqrt(a);
+}
+
+/* native public static double IEEEremainder(double a, double b); */
+static jdouble jieee_remainder(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return remainder(a, b);
+}
+
+/* native public static double floor(double a); */
+static jdouble jfloor(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return floor(a);
+}
+
+/* native public static double ceil(double a); */
+static jdouble jceil(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ceil(a);
+}
+
+/* native public static double rint(double a); */
+static jdouble jrint(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return rint(a);
+}
+
+/* native public static double atan2(double a, double b); */
+static jdouble jatan2(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return atan2(a, b);
+}
+
+/* native public static double pow(double a, double b); */
+static jdouble jpow(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return pow(a, b);
+}
+
+/* native public static double sinh(double a); */
+static jdouble jsinh(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return sinh(a);
+}
+
+/* native public static double tanh(double a); */
+static jdouble jtanh(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return tanh(a);
+}
+
+/* native public static double cosh(double a); */
+static jdouble jcosh(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return cosh(a);
+}
+
+/* native public static double log10(double a); */
+static jdouble jlog10(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return log10(a);
+}
+
+/* native public static double cbrt(double a); */
+static jdouble jcbrt(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return cbrt(a);
+}
+
+/* native public static double expm1(double a); */
+static jdouble jexpm1(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return expm1(a);
+}
+
+/* native public static double hypot(double a, double b); */
+static jdouble jhypot(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return hypot(a, b);
+}
+
+/* native public static double log1p(double a); */
+static jdouble jlog1p(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return log1p(a);
+}
+
+/* native public static double nextafter(double a, double b); */
+static jdouble jnextafter(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return nextafter(a, b);
+}
+
+/* native public static float nextafterf(float a, float b); */
+static jfloat jnextafterf(JNIEnv* env, jclass clazz, jfloat a, jfloat b)
+{
+ return nextafterf(a, b);
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "sin", "(D)D", jsin },
+ { "cos", "(D)D", jcos },
+ { "tan", "(D)D", jtan },
+
+ { "asin", "(D)D", jasin },
+ { "acos", "(D)D", jacos },
+ { "atan", "(D)D", jatan },
+
+ { "exp", "(D)D", jexp },
+ { "log", "(D)D", jlog },
+ { "sqrt", "(D)D", jsqrt },
+
+ { "IEEEremainder", "(DD)D", jieee_remainder },
+
+ { "floor", "(D)D", jfloor },
+ { "ceil", "(D)D", jceil },
+ { "rint", "(D)D", jrint },
+
+ { "atan2", "(DD)D", jatan2 },
+ { "pow", "(DD)D", jpow },
+
+ { "sinh", "(D)D", jsinh },
+ { "cosh", "(D)D", jcosh },
+ { "tanh", "(D)D", jtanh },
+ { "log10", "(D)D", jlog10 },
+ { "cbrt", "(D)D", jcbrt },
+ { "expm1", "(D)D", jexpm1 },
+ { "hypot", "(DD)D", jhypot },
+ { "log1p", "(D)D", jlog1p },
+ { "nextafter", "(DD)D", jnextafter },
+ { "nextafterf", "(FF)F", jnextafterf },
+};
+
+int register_java_lang_Math(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/lang/Math", gMethods,
+ NELEM(gMethods));
+}
diff --git a/luni/src/main/native/java_lang_StrictMath.c b/luni/src/main/native/java_lang_StrictMath.c
new file mode 100644
index 0000000..7d335f7
--- /dev/null
+++ b/luni/src/main/native/java_lang_StrictMath.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Native functions for java.lang.StrictMath.
+ */
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <stdlib.h>
+/* This static way is the "best" way to integrate fdlibm without a conflict
+ * into the android envoirement
+ */
+
+/* #include "fltconst.h" */
+
+#if defined(__P)
+#undef __P
+#endif /* defined(__P) */
+
+#include "../../external/fdlibm/fdlibm.h"
+_LIB_VERSION_TYPE _LIB_VERSION = _IEEE_;
+
+/* native public static double sin(double a); */
+static jdouble jsin(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_sin(a);
+}
+
+/* native public static double cos(double a); */
+static jdouble jcos(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_cos(a);
+}
+
+/* native public static double tan(double a); */
+static jdouble jtan(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_tan(a);
+}
+
+/* native public static double asin(double a); */
+static jdouble jasin(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_asin(a);
+}
+
+/* native public static double acos(double a); */
+static jdouble jacos(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_acos(a);
+}
+
+/* native public static double atan(double a); */
+static jdouble jatan(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_atan(a);
+}
+
+/* native public static double exp(double a); */
+static jdouble jexp(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_exp(a);
+}
+
+/* native public static double log(double a); */
+static jdouble jlog(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_log(a);
+}
+
+/* native public static double sqrt(double a); */
+static jdouble jsqrt2(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_sqrt(a);
+}
+
+/* native public static double IEEEremainder(double a, double b); */
+static jdouble jieee_remainder(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return ieee_remainder(a, b);
+}
+
+/* native public static double floor(double a); */
+static jdouble jfloor(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_floor(a);
+}
+
+/* native public static double ceil(double a); */
+static jdouble jceil(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_ceil(a);
+}
+
+/* native public static double rint(double a); */
+static jdouble jrint(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_rint(a);
+}
+
+/* native public static double atan2(double a, double b); */
+static jdouble jatan2(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return ieee_atan2(a, b);
+}
+
+/* native public static double pow(double a, double b); */
+static jdouble jpow(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return ieee_pow(a,b);
+}
+
+/* native public static double sinh(double a); */
+static jdouble jsinh(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_sinh(a);
+}
+
+/* native public static double tanh(double a); */
+static jdouble jtanh(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_tanh(a);
+}
+
+/* native public static double cosh(double a); */
+static jdouble jcosh(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_cosh(a);
+}
+
+/* native public static double log10(double a); */
+static jdouble jlog10(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_log10(a);
+}
+
+/* native public static double cbrt(double a); */
+static jdouble jcbrt(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_cbrt(a);
+}
+
+/* native public static double expm1(double a); */
+static jdouble jexpm1(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_expm1(a);
+}
+
+/* native public static double hypot(double a, double b); */
+static jdouble jhypot(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return ieee_hypot(a, b);
+}
+
+/* native public static double log1p(double a); */
+static jdouble jlog1p(JNIEnv* env, jclass clazz, jdouble a)
+{
+ return ieee_log1p(a);
+}
+
+/* native public static double nextafter(double a, double b); */
+static jdouble jnextafter(JNIEnv* env, jclass clazz, jdouble a, jdouble b)
+{
+ return ieee_nextafter(a, b);
+}
+
+/* native public static float nextafterf(float a, float b); */
+static jfloat jnextafterf(JNIEnv* env, jclass clazz, jfloat arg1, jfloat arg2)
+{
+ jint hx = *(jint*)&arg1;
+ jint hy = *(jint*)&arg2;
+
+ if (!(hx&0x7fffffff)) { /* arg1 == 0 */
+ *(jint*)&arg1 = (hy & 0x80000000) | 0x1;
+ return arg1;
+ }
+
+ if((hx > 0) ^ (hx > hy)) { /* |arg1| < |arg2| */
+ hx += 1;
+ } else {
+ hx -= 1;
+ }
+ *(jint*)&arg1 = hx;
+ return arg1;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "sin", "(D)D", jsin },
+ { "cos", "(D)D", jcos },
+ { "tan", "(D)D", jtan },
+
+ { "asin", "(D)D", jasin },
+ { "acos", "(D)D", jacos },
+ { "atan", "(D)D", jatan },
+
+ { "exp", "(D)D", jexp },
+ { "log", "(D)D", jlog },
+ { "sqrt", "(D)D", jsqrt2 },
+
+ { "IEEEremainder", "(DD)D", jieee_remainder },
+
+ { "floor", "(D)D", jfloor },
+ { "ceil", "(D)D", jceil },
+ { "rint", "(D)D", jrint },
+
+ { "atan2", "(DD)D", jatan2 },
+ { "pow", "(DD)D", jpow },
+
+ { "sinh", "(D)D", jsinh },
+ { "cosh", "(D)D", jcosh },
+ { "tanh", "(D)D", jtanh },
+ { "log10", "(D)D", jlog10 },
+ { "cbrt", "(D)D", jcbrt },
+ { "expm1", "(D)D", jexpm1 },
+ { "hypot", "(DD)D", jhypot },
+ { "log1p", "(D)D", jlog1p },
+ { "nextafter", "(DD)D", jnextafter },
+ { "nextafterf", "(FF)F", jnextafterf },
+};
+
+int register_java_lang_StrictMath(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, "java/lang/StrictMath", gMethods,
+ NELEM(gMethods));
+}
diff --git a/luni/src/main/native/java_net_InetAddress.cpp b/luni/src/main/native/java_net_InetAddress.cpp
new file mode 100644
index 0000000..cf026bc
--- /dev/null
+++ b/luni/src/main/native/java_net_InetAddress.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InetAddress"
+
+#include "JNIHelp.h"
+#include "utils/Log.h"
+#include "jni.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include <cutils/properties.h>
+#include <cutils/adb_networking.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+
+static jclass byteArrayClass = NULL;
+
+static jstring InetAddress_gethostname(JNIEnv* env, jobject obj)
+{
+ char name[256];
+ int r = gethostname(name, 256);
+ if (r == 0) {
+ return env->NewStringUTF(name);
+ } else {
+ return NULL;
+ }
+}
+
+static void throwNullPointerException(JNIEnv* env)
+{
+ const char* className = "java/lang/NullPointerException";
+
+ jclass exClass = env->FindClass(className);
+
+ if (exClass == NULL) {
+ LOGE("Unable to find class %s", className);
+ } else {
+ env->ThrowNew(exClass, NULL);
+ }
+}
+
+static void logIpString(struct addrinfo* ai, const char* name)
+{
+ char ipString[INET6_ADDRSTRLEN];
+ int result = getnameinfo(ai->ai_addr, ai->ai_addrlen, ipString,
+ sizeof(ipString), NULL, 0, NI_NUMERICHOST);
+ if (result == 0) {
+ LOGD("%s: %s (family %d, proto %d)", name, ipString, ai->ai_family,
+ ai->ai_protocol);
+ } else {
+ LOGE("%s: getnameinfo: %s", name, gai_strerror(result));
+ }
+}
+
+static jobjectArray getAllByNameUsingAdb(JNIEnv* env, const char* name)
+{
+ struct in_addr outaddr;
+ jobjectArray addressArray = NULL;
+ jbyteArray byteArray;
+
+#if 0
+ LOGI("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
+ err, (unsigned int)outaddr.a.s_addr,
+ outaddr.j[0],outaddr.j[1],
+ outaddr.j[2],outaddr.j[3]);
+#endif
+
+ if (adb_networking_gethostbyname(name, &outaddr) >= 0) {
+ addressArray = env->NewObjectArray(1, byteArrayClass, NULL);
+ byteArray = env->NewByteArray(4);
+ if (addressArray && byteArray) {
+ env->SetByteArrayRegion(byteArray, 0, 4, (jbyte*) &outaddr.s_addr);
+ env->SetObjectArrayElement(addressArray, 1, byteArray);
+ }
+ }
+ return addressArray;
+}
+
+static jobjectArray getAllByNameUsingDns(JNIEnv* env, const char* name,
+ jboolean preferIPv4Stack)
+{
+ struct addrinfo hints, *addressList = NULL, *addrInfo;
+ jobjectArray addressArray = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ /*
+ * IPv4 only for now until the socket code supports IPv6; otherwise, the
+ * resolver will create two separate requests, one for IPv4 and one,
+ * currently unnecessary, for IPv6.
+ */
+ hints.ai_family = AF_INET;
+ /*
+ * If we don't specify a socket type, every address will appear twice, once
+ * for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
+ * anyway, just pick one.
+ */
+ hints.ai_socktype = SOCK_STREAM;
+
+ int result = getaddrinfo(name, NULL, &hints, &addressList);
+ if (result == 0 && addressList) {
+ // Count results so we know how to size the output array.
+ int addressCount = 0;
+ for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
+ if (addrInfo->ai_family == AF_INET ||
+ addrInfo->ai_family == AF_INET6) {
+ addressCount++;
+ }
+ }
+
+ // Prepare output array.
+ addressArray = env->NewObjectArray(addressCount, byteArrayClass, NULL);
+ if (addressArray == NULL) {
+ // Appropriate exception will be thrown.
+ LOGE("getAllByNameUsingDns: could not allocate output array");
+ freeaddrinfo(addrInfo);
+ return NULL;
+ }
+
+ // Examine returned addresses one by one, save them in the output array.
+ int index = 0;
+ for (addrInfo = addressList; addrInfo; addrInfo = addrInfo->ai_next) {
+ struct sockaddr* address = addrInfo->ai_addr;
+ size_t addressLength = 0;
+ void* rawAddress;
+
+ switch (addrInfo->ai_family) {
+ // Find the raw address length and start pointer.
+ case AF_INET6:
+ addressLength = 16;
+ rawAddress =
+ &((struct sockaddr_in6*) address)->sin6_addr.s6_addr;
+ logIpString(addrInfo, name);
+ break;
+ case AF_INET:
+ addressLength = 4;
+ rawAddress =
+ &((struct sockaddr_in*) address)->sin_addr.s_addr;
+ logIpString(addrInfo, name);
+ break;
+ default:
+ // Unknown address family. Skip this address.
+ LOGE("getAllByNameUsingDns: Unknown address family %d",
+ addrInfo->ai_family);
+ continue;
+ }
+
+ // Convert each IP address into a Java byte array.
+ jbyteArray bytearray = env->NewByteArray(addressLength);
+ if (bytearray == NULL) {
+ // Out of memory error will be thrown on return.
+ LOGE("getAllByNameUsingDns: Can't allocate %d-byte array",
+ addressLength);
+ addressArray = NULL;
+ break;
+ }
+ env->SetByteArrayRegion(bytearray, 0, addressLength,
+ (jbyte*) rawAddress);
+ env->SetObjectArrayElement(addressArray, index, bytearray);
+ env->DeleteLocalRef(bytearray);
+ index++;
+ }
+ } else if (result == EAI_SYSTEM && errno == EACCES) {
+ /* No permission to use network */
+ jniThrowException(
+ env, "java/lang/SecurityException",
+ "Permission denied (maybe missing INTERNET permission)");
+ } else {
+ // Do nothing. Return value will be null and the caller will throw an
+ // UnknownHostExeption.
+ }
+
+ if (addressList) {
+ freeaddrinfo(addressList);
+ }
+
+ return addressArray;
+}
+
+jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj,
+ jstring javaName,
+ jboolean preferIPv4Stack)
+{
+ if (javaName == NULL) {
+ throwNullPointerException(env);
+ return NULL;
+ }
+
+ const char* name = env->GetStringUTFChars(javaName, NULL);
+ jobjectArray out = NULL;
+
+ char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
+ char adbConnected[PROPERTY_VALUE_MAX];
+ property_get("android.net.use-adb-networking",
+ useAdbNetworkingProperty, "");
+ property_get("adb.connected",
+ adbConnected, "");
+
+ // Any non-empty string value for use-adb-networking is considered "set"
+ if ((strlen(useAdbNetworkingProperty) > 0)
+ && (strlen(adbConnected) > 0) ) {
+ out = getAllByNameUsingAdb(env, name);
+ } else {
+ out = getAllByNameUsingDns(env, name, preferIPv4Stack);
+ }
+
+ if (!out) {
+ LOGI("Unknown host %s, throwing UnknownHostException", name);
+ jniThrowException(env, "java/net/UnknownHostException", name);
+ }
+ env->ReleaseStringUTFChars(javaName, name);
+ return out;
+}
+
+
+static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
+ jbyteArray javaAddress)
+{
+ if (javaAddress == NULL) {
+ throwNullPointerException(env);
+ return NULL;
+ }
+
+ size_t addrlen = env->GetArrayLength(javaAddress);
+ jbyte* rawAddress = env->GetByteArrayElements(javaAddress, NULL);
+ if (rawAddress == NULL) {
+ throwNullPointerException(env);
+ return NULL;
+ }
+
+ // Convert the raw address bytes into a socket address structure.
+ struct sockaddr_storage ss;
+ struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
+ size_t socklen;
+ switch (addrlen) {
+ case 4:
+ socklen = sizeof(struct sockaddr_in);
+ memset(sin, 0, sizeof(struct sockaddr_in));
+ sin->sin_family = AF_INET;
+ memcpy(&sin->sin_addr.s_addr, rawAddress, 4);
+ break;
+ case 16:
+ socklen = sizeof(struct sockaddr_in6);
+ memset(sin6, 0, sizeof(struct sockaddr_in6));
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr.s6_addr, rawAddress, 4);
+ break;
+ default:
+ jniThrowException(env, "java/net/UnknownHostException",
+ "Invalid address length");
+ return NULL;
+ }
+
+
+ // Convert the socket address structure to an IP string for logging.
+ int ret;
+ char ipstr[INET6_ADDRSTRLEN];
+ ret = getnameinfo((struct sockaddr *) &ss, socklen, ipstr, sizeof(ipstr),
+ NULL, 0, NI_NUMERICHOST);
+ if (ret) {
+ LOGE("gethostbyaddr: getnameinfo: %s", gai_strerror(ret));
+ return NULL;
+ }
+
+ // Look up the IP address from the socket address structure.
+ jstring result = NULL;
+ char name[NI_MAXHOST];
+ ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
+ NULL, 0, 0);
+ if (ret == 0) {
+ LOGI("gethostbyaddr: getnameinfo: %s = %s", ipstr, name);
+ result = env->NewStringUTF(name);
+ } else {
+ LOGE("gethostbyaddr: getnameinfo: unknown host %s: %s", ipstr,
+ gai_strerror(ret));
+ }
+
+ return result;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "gethostbyaddr", "([B)Ljava/lang/String;",
+ (void*) InetAddress_gethostbyaddr },
+ { "getallbyname", "(Ljava/lang/String;Z)[[B",
+ (void*) InetAddress_getallbyname },
+ { "gethostname", "()Ljava/lang/String;",
+ (void*) InetAddress_gethostname },
+};
+
+extern "C" int register_java_net_InetAddress(JNIEnv* env)
+{
+ jclass tempClass = env->FindClass("[B");
+ if (tempClass) {
+ byteArrayClass = (jclass) env->NewGlobalRef(tempClass);
+ }
+ if (!byteArrayClass) {
+ LOGE("register_java_net_InetAddress: cannot allocate byte array class");
+ return -1;
+ }
+ return jniRegisterNativeMethods(env, "java/net/InetAddress",
+ gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/java_net_NetworkInterface.c b/luni/src/main/native/java_net_NetworkInterface.c
new file mode 100644
index 0000000..379ccdf
--- /dev/null
+++ b/luni/src/main/native/java_net_NetworkInterface.c
@@ -0,0 +1,844 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "errno.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+
+//--------------------------------------------------------------------
+// TODO copied from OSNetworkSystem. Might get into a separate .h file
+/**
+ * Throws an IOException with the given message.
+ */
+static void throwSocketException(JNIEnv *env, const char *message) {
+ jclass exClass = (*env)->FindClass(env, "java/net/SocketException");
+
+ if(exClass == NULL) {
+ LOGE("Unable to find class java/net/SocketException");
+ } else {
+ (*env)->ThrowNew(env, exClass, message);
+ }
+}
+
+
+/**
+ * Throws a NullPointerException.
+ */
+static void throwNullPointerException(JNIEnv *env) {
+ jclass exClass = (*env)->FindClass(env, "java/lang/NullPointerException");
+
+ if(exClass == NULL) {
+ LOGE("Unable to find class java/lang/NullPointerException");
+ } else {
+ (*env)->ThrowNew(env, exClass, NULL);
+ }
+}
+
+/**
+ * @name Socket Errors
+ * Error codes for socket operations
+ *
+ * @internal SOCKERR* range from -200 to -299 avoid overlap
+ */
+#define SOCKERR_BADSOCKET -200 /* generic error */
+#define SOCKERR_NOTINITIALIZED -201 /* socket library uninitialized */
+#define SOCKERR_BADAF -202 /* bad address family */
+#define SOCKERR_BADPROTO -203 /* bad protocol */
+#define SOCKERR_BADTYPE -204 /* bad type */
+#define SOCKERR_SYSTEMBUSY -205 /* system busy handling requests */
+#define SOCKERR_SYSTEMFULL -206 /* too many sockets */
+#define SOCKERR_NOTCONNECTED -207 /* socket is not connected */
+#define SOCKERR_INTERRUPTED -208 /* the call was cancelled */
+#define SOCKERR_TIMEOUT -209 /* the operation timed out */
+#define SOCKERR_CONNRESET -210 /* the connection was reset */
+#define SOCKERR_WOULDBLOCK -211 /* the socket is marked as nonblocking operation would block */
+#define SOCKERR_ADDRNOTAVAIL -212 /* address not available */
+#define SOCKERR_ADDRINUSE -213 /* address already in use */
+#define SOCKERR_NOTBOUND -214 /* the socket is not bound */
+#define SOCKERR_UNKNOWNSOCKET -215 /* resolution of fileDescriptor to socket failed */
+#define SOCKERR_INVALIDTIMEOUT -216 /* the specified timeout is invalid */
+#define SOCKERR_FDSETFULL -217 /* Unable to create an FDSET */
+#define SOCKERR_TIMEVALFULL -218 /* Unable to create a TIMEVAL */
+#define SOCKERR_REMSOCKSHUTDOWN -219 /* The remote socket has shutdown gracefully */
+#define SOCKERR_NOTLISTENING -220 /* listen() was not invoked prior to accept() */
+#define SOCKERR_NOTSTREAMSOCK -221 /* The socket does not support connection-oriented service */
+#define SOCKERR_ALREADYBOUND -222 /* The socket is already bound to an address */
+#define SOCKERR_NBWITHLINGER -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
+#define SOCKERR_ISCONNECTED -224 /* The socket is already connected */
+#define SOCKERR_NOBUFFERS -225 /* No buffer space is available */
+#define SOCKERR_HOSTNOTFOUND -226 /* Authoritative Answer Host not found */
+#define SOCKERR_NODATA -227 /* Valid name, no data record of requested type */
+#define SOCKERR_BOUNDORCONN -228 /* The socket has not been bound or is already connected */
+#define SOCKERR_OPNOTSUPP -229 /* The socket does not support the operation */
+#define SOCKERR_OPTUNSUPP -230 /* The socket option is not supported */
+#define SOCKERR_OPTARGSINVALID -231 /* The socket option arguments are invalid */
+#define SOCKERR_SOCKLEVELINVALID -232 /* The socket level is invalid */
+#define SOCKERR_TIMEOUTFAILURE -233
+#define SOCKERR_SOCKADDRALLOCFAIL -234 /* Unable to allocate the sockaddr structure */
+#define SOCKERR_FDSET_SIZEBAD -235 /* The calculated maximum size of the file descriptor set is bad */
+#define SOCKERR_UNKNOWNFLAG -236 /* The flag is unknown */
+#define SOCKERR_MSGSIZE -237 /* The datagram was too big to fit the specified buffer & was truncated. */
+#define SOCKERR_NORECOVERY -238 /* The operation failed with no recovery possible */
+#define SOCKERR_ARGSINVALID -239 /* The arguments are invalid */
+#define SOCKERR_BADDESC -240 /* The socket argument is not a valid file descriptor */
+#define SOCKERR_NOTSOCK -241 /* The socket argument is not a socket */
+#define SOCKERR_HOSTENTALLOCFAIL -242 /* Unable to allocate the hostent structure */
+#define SOCKERR_TIMEVALALLOCFAIL -243 /* Unable to allocate the timeval structure */
+#define SOCKERR_LINGERALLOCFAIL -244 /* Unable to allocate the linger structure */
+#define SOCKERR_IPMREQALLOCFAIL -245 /* Unable to allocate the ipmreq structure */
+#define SOCKERR_FDSETALLOCFAIL -246 /* Unable to allocate the fdset structure */
+#define SOCKERR_OPFAILED -247
+#define SOCKERR_VALUE_NULL -248 /* The value indexed was NULL */
+#define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
+#define SOCKERR_ENETUNREACH -250 /* network is not reachable */
+#define SOCKERR_EACCES -251 /* permissions do not allow action on socket */
+
+/**
+ * Answer the errorString corresponding to the errorNumber, if available.
+ * This function will answer a default error string, if the errorNumber is not
+ * recognized.
+ *
+ * This function will have to be reworked to handle internationalization properly, removing
+ * the explicit strings.
+ *
+ * @param anErrorNum the error code to resolve to a human readable string
+ *
+ * @return a human readable error string
+ */
+
+static char * netLookupErrorString(int anErrorNum) {
+ switch(anErrorNum) {
+ case SOCKERR_BADSOCKET:
+ return "Bad socket";
+ case SOCKERR_NOTINITIALIZED:
+ return "Socket library uninitialized";
+ case SOCKERR_BADAF:
+ return "Bad address family";
+ case SOCKERR_BADPROTO:
+ return "Bad protocol";
+ case SOCKERR_BADTYPE:
+ return "Bad type";
+ case SOCKERR_SYSTEMBUSY:
+ return "System busy handling requests";
+ case SOCKERR_SYSTEMFULL:
+ return "Too many sockets allocated";
+ case SOCKERR_NOTCONNECTED:
+ return "Socket is not connected";
+ case SOCKERR_INTERRUPTED:
+ return "The call was cancelled";
+ case SOCKERR_TIMEOUT:
+ return "The operation timed out";
+ case SOCKERR_CONNRESET:
+ return "The connection was reset";
+ case SOCKERR_WOULDBLOCK:
+ return "The socket is marked as nonblocking operation would block";
+ case SOCKERR_ADDRNOTAVAIL:
+ return "The address is not available";
+ case SOCKERR_ADDRINUSE:
+ return "The address is already in use";
+ case SOCKERR_NOTBOUND:
+ return "The socket is not bound";
+ case SOCKERR_UNKNOWNSOCKET:
+ return "Resolution of the FileDescriptor to socket failed";
+ case SOCKERR_INVALIDTIMEOUT:
+ return "The specified timeout is invalid";
+ case SOCKERR_FDSETFULL:
+ return "Unable to create an FDSET";
+ case SOCKERR_TIMEVALFULL:
+ return "Unable to create a TIMEVAL";
+ case SOCKERR_REMSOCKSHUTDOWN:
+ return "The remote socket has shutdown gracefully";
+ case SOCKERR_NOTLISTENING:
+ return "Listen() was not invoked prior to accept()";
+ case SOCKERR_NOTSTREAMSOCK:
+ return "The socket does not support connection-oriented service";
+ case SOCKERR_ALREADYBOUND:
+ return "The socket is already bound to an address";
+ case SOCKERR_NBWITHLINGER:
+ return "The socket is marked non-blocking & SO_LINGER is non-zero";
+ case SOCKERR_ISCONNECTED:
+ return "The socket is already connected";
+ case SOCKERR_NOBUFFERS:
+ return "No buffer space is available";
+ case SOCKERR_HOSTNOTFOUND:
+ return "Authoritative Answer Host not found";
+ case SOCKERR_NODATA:
+ return "Valid name, no data record of requested type";
+ case SOCKERR_BOUNDORCONN:
+ return "The socket has not been bound or is already connected";
+ case SOCKERR_OPNOTSUPP:
+ return "The socket does not support the operation";
+ case SOCKERR_OPTUNSUPP:
+ return "The socket option is not supported";
+ case SOCKERR_OPTARGSINVALID:
+ return "The socket option arguments are invalid";
+ case SOCKERR_SOCKLEVELINVALID:
+ return "The socket level is invalid";
+ case SOCKERR_TIMEOUTFAILURE:
+ return "The timeout operation failed";
+ case SOCKERR_SOCKADDRALLOCFAIL:
+ return "Failed to allocate address structure";
+ case SOCKERR_FDSET_SIZEBAD:
+ return "The calculated maximum size of the file descriptor set is bad";
+ case SOCKERR_UNKNOWNFLAG:
+ return "The flag is unknown";
+ case SOCKERR_MSGSIZE:
+ return "The datagram was too big to fit the specified buffer, so truncated";
+ case SOCKERR_NORECOVERY:
+ return "The operation failed with no recovery possible";
+ case SOCKERR_ARGSINVALID:
+ return "The arguments are invalid";
+ case SOCKERR_BADDESC:
+ return "The socket argument is not a valid file descriptor";
+ case SOCKERR_NOTSOCK:
+ return "The socket argument is not a socket";
+ case SOCKERR_HOSTENTALLOCFAIL:
+ return "Unable to allocate the hostent structure";
+ case SOCKERR_TIMEVALALLOCFAIL:
+ return "Unable to allocate the timeval structure";
+ case SOCKERR_LINGERALLOCFAIL:
+ return "Unable to allocate the linger structure";
+ case SOCKERR_IPMREQALLOCFAIL:
+ return "Unable to allocate the ipmreq structure";
+ case SOCKERR_FDSETALLOCFAIL:
+ return "Unable to allocate the fdset structure";
+ case SOCKERR_CONNECTION_REFUSED:
+ return "Connection refused";
+
+ default:
+ return "unkown error";
+ }
+}
+
+/**
+ * Converts a native address structure to a 4-byte array. Throws a
+ * NullPointerException or an IOException in case of error. This is
+ * signaled by a return value of -1. The normal return value is 0.
+ */
+static int structInToJavaAddress(
+ JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
+
+ if(java_address == NULL) {
+ throwNullPointerException(env);
+ return -1;
+ }
+
+ if((*env)->GetArrayLength(env, java_address) != sizeof(address->s_addr)) {
+ jniThrowIOException(env, errno);
+ return -1;
+ }
+
+ jbyte *java_address_bytes;
+
+ java_address_bytes = (*env)->GetByteArrayElements(env, java_address, NULL);
+
+ memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
+
+ (*env)->ReleaseByteArrayElements(env, java_address, java_address_bytes, 0);
+
+ return 0;
+}
+
+static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
+ jbyteArray bytes;
+ int success;
+
+ bytes = (*env)->NewByteArray(env, 4);
+
+ if(bytes == NULL) {
+ return NULL;
+ }
+
+ success = structInToJavaAddress(env, address, bytes);
+
+ if(success < 0) {
+ return NULL;
+ }
+
+ jclass iaddrclass = (*env)->FindClass(env, "java/net/InetAddress");
+
+ if(iaddrclass == NULL) {
+ LOGE("Can't find java/net/InetAddress");
+ jniThrowException(env, "java/lang/ClassNotFoundException", "java.net.InetAddress");
+ return NULL;
+ }
+
+ jmethodID iaddrgetbyaddress = (*env)->GetStaticMethodID(env, iaddrclass, "getByAddress", "([B)Ljava/net/InetAddress;");
+
+ if(iaddrgetbyaddress == NULL) {
+ LOGE("Can't find method InetAddress.getByAddress(byte[] val)");
+ jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.getByAddress(byte[] val)");
+ return NULL;
+ }
+
+ return (*env)->CallStaticObjectMethod(env, iaddrclass, iaddrgetbyaddress, bytes);
+}
+//--------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* structure for returning either and IPV4 or IPV6 ip address */
+typedef struct ipAddress_struct {
+ union {
+ char bytes[sizeof(struct in_addr)];
+ struct in_addr inAddr;
+ } addr;
+ unsigned int length;
+ unsigned int scope;
+} ipAddress_struct;
+
+/* structure for returning network interface information */
+typedef struct NetworkInterface_struct {
+ char *name;
+ char *displayName;
+ unsigned int numberAddresses;
+ unsigned int index;
+ struct ipAddress_struct *addresses;
+} NetworkInterface_struct;
+
+/* array of network interface structures */
+typedef struct NetworkInterfaceArray_struct {
+ unsigned int length;
+ struct NetworkInterface_struct *elements;
+} NetworkInterfaceArray_struct;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * Frees the memory allocated for the hyNetworkInterface_struct array passed in
+ *
+ * @param[in] portLibrary The port library.
+ * @param[in] handle Pointer to array of network interface structures to be freed
+ *
+ * @return 0 on success
+*/
+int sock_free_network_interface_struct (struct NetworkInterfaceArray_struct *array) {
+ unsigned int i = 0;
+
+ if((array != NULL) && (array->elements != NULL)) {
+
+ /* free the allocated memory in each of the structures */
+ for(i = 0; i < array->length; i++) {
+
+ /* free the name, displayName and addresses */
+ if(array->elements[i].name != NULL) {
+ free(array->elements[i].name);
+ }
+
+ if(array->elements[i].displayName != NULL) {
+ free(array->elements[i].displayName);
+ }
+
+ if(array->elements[i].addresses != NULL) {
+ free(array->elements[i].addresses);
+ }
+ }
+
+ /* now free the array itself */
+ free(array->elements);
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * Queries and returns the information for the network interfaces that are currently active within the system.
+ * Applications are responsible for freeing the memory returned via the handle.
+ *
+ * @param[in] portLibrary The port library.
+ * @param[in,out] array Pointer to structure with array of network interface entries
+ * @param[in] boolean which indicates if we should prefer the IPv4 stack or not
+ *
+ * @return The number of elements in handle on success, negatvie portable error code on failure.
+ -WSANO_RECOVERY if system calls required to get the info fail, -WSAENOBUFS if memory allocation fails
+ * @note A return value of 0 indicates no interfaces exist
+*/
+int sockGetNetworkInterfaces(struct NetworkInterfaceArray_struct * array) {
+
+ struct NetworkInterface_struct *interfaces = NULL;
+ unsigned int nameLength = 0;
+ unsigned int currentAdapterIndex = 0;
+ unsigned int counter = 0;
+ unsigned int result = 0;
+ unsigned int numAddresses = 0;
+ unsigned int currentIPAddressIndex = 0;
+ unsigned int numAdapters = 0;
+ int err = 0;
+
+ struct ifconf ifc;
+ int len = 32 * sizeof(struct ifreq);
+ int socketP = 0;
+ unsigned int totalInterfaces = 0;
+ struct ifreq reqCopy;
+ unsigned int counter2 = 0;
+ char *lastName = NULL;
+
+ int ifconfCommand = SIOCGIFCONF;
+
+ /* this method is not guarranteed to return the IPV6 addresses. Code is include so that if the platform returns IPV6 addresses
+ in reply to the SIOCGIFCONF they will be included. Howerver, it is not guarranteed or even expected that many platforms will
+ include the IPV6 addresses. For this reason there are other specific implementations that will return the IPV6 addresses */
+ /* first get the list of interfaces. We do not know how long the buffer needs to be so we try with one that allows for
+ 32 interfaces. If this turns out not to be big enough then we expand the buffer to be able to support another
+ 32 interfaces and try again. We do this until the result indicates that the result fit into the buffer provided */
+ /* we need socket to do the ioctl so create one */
+ socketP = socket(PF_INET, SOCK_DGRAM, 0);
+ if(socketP < 0) {
+ return socketP;
+ }
+ for(;;) {
+ char *data = (char *)malloc(len * sizeof(char));
+ if(data == NULL) {
+ close(socketP);
+ return SOCKERR_NOBUFFERS;
+ }
+ ifc.ifc_len = len;
+ ifc.ifc_buf = data;
+ errno = 0;
+ if(ioctl(socketP, ifconfCommand, &ifc) != 0) {
+ err = errno;
+ free(ifc.ifc_buf);
+ close(socketP);
+ return SOCKERR_NORECOVERY;
+ }
+ if(ifc.ifc_len < len)
+ break;
+ /* the returned data was likely truncated, expand the buffer and try again */
+ free(ifc.ifc_buf);
+ len += 32 * sizeof(struct ifreq);
+ }
+
+ /* get the number of distinct interfaces */
+ if(ifc.ifc_len != 0) {
+ totalInterfaces = ifc.ifc_len / sizeof(struct ifreq);
+ }
+ lastName = NULL;
+ for(counter = 0; counter < totalInterfaces; counter++) {
+ if((NULL == lastName) || (strncmp(lastName, ifc.ifc_req[counter].ifr_name, IFNAMSIZ) != 0)) {
+ /* make sure the interface is up */
+ reqCopy = ifc.ifc_req[counter];
+ ioctl(socketP, SIOCGIFFLAGS, &reqCopy);
+ if((reqCopy.ifr_flags) & (IFF_UP == IFF_UP)) {
+ numAdapters++;
+ }
+ }
+ lastName = ifc.ifc_req[counter].ifr_name;
+ }
+
+ /* now allocate the space for the hyNetworkInterface structs and fill it in */
+ interfaces = malloc(numAdapters * sizeof(NetworkInterface_struct));
+ if(NULL == interfaces) {
+ free(ifc.ifc_buf);
+ close(socketP);
+ return SOCKERR_NOBUFFERS;
+ }
+
+ /* initialize the structure so that we can free allocated if a failure occurs */
+ for(counter = 0; counter < numAdapters; counter++) {
+ interfaces[counter].name = NULL;
+ interfaces[counter].displayName = NULL;
+ interfaces[counter].addresses = NULL;
+ }
+
+ /* set up the return stucture */
+ array->elements = interfaces;
+ array->length = numAdapters;
+ lastName = NULL;
+ for(counter = 0; counter < totalInterfaces; counter++) {
+ /* make sure the interface is still up */
+ reqCopy = ifc.ifc_req[counter];
+ ioctl(socketP, SIOCGIFFLAGS, &reqCopy);
+ if((reqCopy.ifr_flags) & (IFF_UP == IFF_UP)) {
+ /* since this function can return multiple entries for the same name, only do it for the first one with any given name */
+ if((NULL == lastName) || (strncmp(lastName, ifc.ifc_req[counter].ifr_name, IFNAMSIZ) != 0)) {
+
+ /* get the index for the interface. This is only truely necessary on platforms that support IPV6 */
+ interfaces[currentAdapterIndex].index = 0;
+ /* get the name and display name for the adapter */
+ /* there only seems to be one name so use it for both the name and the display name */
+ nameLength = strlen(ifc.ifc_req[counter].ifr_name);
+ interfaces[currentAdapterIndex].name = malloc(nameLength + 1);
+
+ if(NULL == interfaces[currentAdapterIndex].name) {
+ free(ifc.ifc_buf);
+ sock_free_network_interface_struct(array);
+ close(socketP);
+ return SOCKERR_NOBUFFERS;
+ }
+ strncpy(interfaces[currentAdapterIndex].name, ifc.ifc_req[counter].ifr_name, nameLength);
+ interfaces[currentAdapterIndex].name[nameLength] = 0;
+ nameLength = strlen(ifc.ifc_req[counter].ifr_name);
+ interfaces[currentAdapterIndex].displayName = malloc(nameLength + 1);
+ if(NULL == interfaces[currentAdapterIndex].displayName) {
+ free(ifc.ifc_buf);
+ sock_free_network_interface_struct(array);
+ close(socketP);
+ return SOCKERR_NOBUFFERS;
+ }
+ strncpy(interfaces[currentAdapterIndex].displayName, ifc.ifc_req[counter].ifr_name, nameLength);
+ interfaces[currentAdapterIndex].displayName[nameLength] = 0;
+
+ /* check how many addresses/aliases this adapter has. aliases show up as adaptors with the same name */
+ numAddresses = 0;
+ for(counter2 = counter; counter2 < totalInterfaces; counter2++) {
+ if(strncmp(ifc.ifc_req[counter].ifr_name, ifc.ifc_req[counter2].ifr_name, IFNAMSIZ) == 0) {
+ if(ifc.ifc_req[counter2].ifr_addr.sa_family == AF_INET) {
+ numAddresses++;
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* allocate space for the addresses */
+ interfaces[currentAdapterIndex].numberAddresses = numAddresses;
+ interfaces[currentAdapterIndex].addresses = malloc(numAddresses * sizeof(ipAddress_struct));
+ if(NULL == interfaces[currentAdapterIndex].addresses) {
+ free(ifc.ifc_buf);
+ sock_free_network_interface_struct(array);
+ close(socketP);
+ return SOCKERR_NOBUFFERS;
+ }
+
+ /* now get the addresses */
+ currentIPAddressIndex = 0;
+ lastName = ifc.ifc_req[counter].ifr_name;
+
+ for(;;) {
+ if(ifc.ifc_req[counter].ifr_addr.sa_family == AF_INET) {
+ interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].addr.inAddr.s_addr = ((struct sockaddr_in *) (&ifc.ifc_req[counter].ifr_addr))->sin_addr.s_addr;
+ interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].length = sizeof(struct in_addr);
+ interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].scope = 0;
+ currentIPAddressIndex++;
+ }
+
+ /* we mean to increment the outside counter here as we want to skip the next entry as it is for the same interface
+ as we are currently working on */
+ if((counter + 1 < totalInterfaces) && (strncmp(ifc.ifc_req[counter + 1].ifr_name, lastName, IFNAMSIZ) == 0)) {
+ counter++;
+ } else {
+ break;
+ }
+
+ }
+ currentAdapterIndex++;
+ }
+ }
+ } /* for over all interfaces */
+ /* now an interface might have been taken down since we first counted them */
+ array->length = currentAdapterIndex;
+ /* free the memory now that we are done with it */
+ free(ifc.ifc_buf);
+ close(socketP);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * Answer an array of NetworkInterface objects. One for each network interface within the system
+ *
+ * @param env pointer to the JNI library
+ * @param clazz the class of the object invoking the JNI function
+ *
+ * @return an array of NetworkInterface objects of length 0 or more
+ */
+
+static jobjectArray getNetworkInterfacesImpl(JNIEnv * env, jclass clazz) {
+
+ /* variables to store network interfac edata returned by call to port library */
+ struct NetworkInterfaceArray_struct networkInterfaceArray;
+ int result = 0;
+
+ /* variables for class and method objects needed to create bridge to java */
+ jclass networkInterfaceClass = NULL;
+ jclass inetAddressClass = NULL;
+ jclass utilClass = NULL;
+ jmethodID methodID = NULL;
+ jmethodID utilMid = NULL;
+
+ /* JNI objects used to return values from native call */
+ jstring name = NULL;
+ jstring displayName = NULL;
+ jobjectArray addresses = NULL;
+ jobjectArray networkInterfaces = NULL;
+ jbyteArray bytearray = NULL;
+
+ /* jobjects used to build the object arrays returned */
+ jobject currentInterface = NULL;
+ jobject element = NULL;
+
+ /* misc variables needed for looping and determining inetAddress info */
+ unsigned int i = 0;
+ unsigned int j = 0;
+ unsigned int nameLength = 0;
+
+ /* get the classes and methods that we need for later calls */
+ networkInterfaceClass = (*env)->FindClass(env, "java/net/NetworkInterface");
+ if(networkInterfaceClass == NULL) {
+ throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY));
+ return NULL;
+ }
+
+ inetAddressClass = (*env)->FindClass(env, "java/net/InetAddress");
+ if(inetAddressClass == NULL) {
+ throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY));
+ return NULL;
+ }
+
+ methodID = (*env)->GetMethodID(env, networkInterfaceClass, "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;[Ljava/net/InetAddress;I)V");
+ if(methodID == NULL) {
+ throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY));
+ return NULL;
+ }
+
+ utilClass = (*env)->FindClass(env, "org/apache/harmony/luni/util/Util");
+ if(!utilClass) {
+ return NULL;
+ }
+
+ utilMid = ((*env)->GetStaticMethodID(env, utilClass, "toString",
+ "([BII)Ljava/lang/String;"));
+ if(!utilMid) {
+ return NULL;
+ }
+
+ result = sockGetNetworkInterfaces(&networkInterfaceArray);
+
+ if(result < 0) {
+ /* this means an error occured. The value returned is the socket error that should be returned */
+ throwSocketException(env, netLookupErrorString(result));
+ return NULL;
+ }
+
+ /* now loop through the interfaces and extract the information to be returned */
+ for(j = 0; j < networkInterfaceArray.length; j++) {
+ /* set the name and display name and reset the addresses object array */
+ addresses = NULL;
+ name = NULL;
+ displayName = NULL;
+
+ if(networkInterfaceArray.elements[j].name != NULL) {
+ nameLength = strlen(networkInterfaceArray.elements[j].name);
+ bytearray = (*env)->NewByteArray(env, nameLength);
+ if(bytearray == NULL) {
+ /* NewByteArray should have thrown an exception */
+ return NULL;
+ }
+ (*env)->SetByteArrayRegion(env, bytearray, (jint) 0, nameLength,
+ (jbyte *)networkInterfaceArray.elements[j].name);
+ name = (*env)->CallStaticObjectMethod(env, utilClass, utilMid,
+ bytearray, (jint) 0, nameLength);
+ if((*env)->ExceptionCheck(env)) {
+ return NULL;
+ }
+ }
+
+ if(networkInterfaceArray.elements[j].displayName != NULL) {
+ nameLength = strlen(networkInterfaceArray.elements[j].displayName);
+ bytearray = (*env)->NewByteArray(env, nameLength);
+ if(bytearray == NULL) {
+ /* NewByteArray should have thrown an exception */
+ return NULL;
+ }
+ (*env)->SetByteArrayRegion(env, bytearray, (jint) 0, nameLength,
+ (jbyte *)networkInterfaceArray.elements[j].displayName);
+ displayName = (*env)->CallStaticObjectMethod(env, utilClass, utilMid,
+ bytearray, (jint) 0, nameLength);
+ if((*env)->ExceptionCheck(env)) {
+ return NULL;
+ }
+ }
+
+ /* generate the object with the inet addresses for the itnerface */
+ for(i = 0; i < networkInterfaceArray.elements[j].numberAddresses; i++) {
+ element = structInToInetAddress(env, (struct in_addr *) &(networkInterfaceArray.elements[j].addresses[i].addr.inAddr));
+ if(i == 0) {
+ addresses = (*env)->NewObjectArray(env,
+ networkInterfaceArray.elements[j].numberAddresses,
+ inetAddressClass, element);
+ } else {
+ (*env)->SetObjectArrayElement(env, addresses, i, element);
+ }
+ }
+
+ /* now create the NetworkInterface object for this interface and then add it it ot the arrary that will be returned */
+ currentInterface = (*env)->NewObject(env, networkInterfaceClass,
+ methodID, name, displayName, addresses,
+ networkInterfaceArray.elements[j].index);
+
+ if(j == 0) {
+ networkInterfaces = (*env)->NewObjectArray(env,
+ networkInterfaceArray.length, networkInterfaceClass,
+ currentInterface);
+ } else {
+ (*env)->SetObjectArrayElement(env, networkInterfaces, j, currentInterface);
+ }
+ }
+
+ /* free the memory for the interfaces struct and return the new NetworkInterface List */
+ sock_free_network_interface_struct(&networkInterfaceArray);
+ return networkInterfaces;
+}
+
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "getNetworkInterfacesImpl", "()[Ljava/net/NetworkInterface;", getNetworkInterfacesImpl }
+};
+int register_java_net_NetworkInterface(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "java/net/NetworkInterface",
+ gMethods, NELEM(gMethods));
+
+}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
new file mode 100644
index 0000000..38f3d36
--- /dev/null
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
@@ -0,0 +1,807 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Common natives supporting the file system interface.
+ */
+
+#define HyMaxPath 1024
+#define HyOpenRead 1 /* Values for HyFileOpen */
+#define HyOpenWrite 2
+#define HyOpenCreate 4
+#define HyOpenTruncate 8
+#define HyOpenAppend 16
+#define HyOpenText 32
+
+/* Use this flag with HyOpenCreate, if this flag is specified then
+ * trying to create an existing file will fail
+ */
+#define HyOpenCreateNew 64
+#define HyOpenSync 128
+#define SHARED_LOCK_TYPE 1L
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/sendfile.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+typedef struct socket_struct {
+ int sock;
+ unsigned short family;
+} socket_struct;
+
+static void convertToPlatform(char *path) {
+ char *pathIndex;
+
+ pathIndex = path;
+ while (*pathIndex != '\0') {
+ if(*pathIndex == '\\') {
+ *pathIndex = '/';
+ }
+ pathIndex++;
+ }
+}
+
+static int
+EsTranslateOpenFlags(int flags) {
+ int realFlags = 0;
+
+ if(flags & HyOpenAppend) {
+ realFlags |= O_APPEND;
+ }
+ if(flags & HyOpenTruncate) {
+ realFlags |= O_TRUNC;
+ }
+ if(flags & HyOpenCreate) {
+ realFlags |= O_CREAT;
+ }
+ if(flags & HyOpenCreateNew) {
+ realFlags |= O_EXCL | O_CREAT;
+ }
+#ifdef O_SYNC
+ if(flags & HyOpenSync) {
+ realFlags |= O_SYNC;
+ }
+#endif
+ if(flags & HyOpenRead) {
+ if(flags & HyOpenWrite) {
+ return (O_RDWR | realFlags);
+ }
+ return (O_RDONLY | realFlags);
+ }
+ if(flags & HyOpenWrite) {
+ return (O_WRONLY | realFlags);
+ }
+ return -1;
+}
+
+/**
+ * Lock the file identified by the given handle.
+ * The range and lock type are given.
+ */
+static jint harmony_io_lockImpl(JNIEnv * env, jobject thiz, jint handle,
+ jlong start, jlong length, jint typeFlag, jboolean waitFlag) {
+
+ int rc;
+ int waitMode = (waitFlag) ? F_SETLKW : F_SETLK;
+ struct flock lock;
+
+ memset(&lock, 0, sizeof(lock));
+
+ // If start or length overflow the max values we can represent, then max them out.
+ if(start > 0x7fffffffL) {
+ start = 0x7fffffffL;
+ }
+ if(length > 0x7fffffffL) {
+ length = 0x7fffffffL;
+ }
+
+ lock.l_whence = SEEK_SET;
+ lock.l_start = start;
+ lock.l_len = length;
+
+ if((typeFlag & SHARED_LOCK_TYPE) == SHARED_LOCK_TYPE) {
+ lock.l_type = F_RDLCK;
+ } else {
+ lock.l_type = F_WRLCK;
+ }
+
+ do {
+ rc = fcntl(handle, waitMode, &lock);
+ } while ((rc < 0) && (errno == EINTR));
+
+ return (rc == -1) ? -1 : 0;
+}
+
+/**
+ * Unlocks the specified region of the file.
+ */
+static jint harmony_io_unlockImpl(JNIEnv * env, jobject thiz, jint handle,
+ jlong start, jlong length) {
+
+ int rc;
+ struct flock lock;
+
+ memset(&lock, 0, sizeof(lock));
+
+ // If start or length overflow the max values we can represent, then max them out.
+ if(start > 0x7fffffffL) {
+ start = 0x7fffffffL;
+ }
+ if(length > 0x7fffffffL) {
+ length = 0x7fffffffL;
+ }
+
+ lock.l_whence = SEEK_SET;
+ lock.l_start = start;
+ lock.l_len = length;
+ lock.l_type = F_UNLCK;
+
+ do {
+ rc = fcntl(handle, F_SETLKW, &lock);
+ } while ((rc < 0) && (errno == EINTR));
+
+ return (rc == -1) ? -1 : 0;
+}
+
+/**
+ * Returns the granularity of the starting address for virtual memory allocation.
+ * (It's the same as the page size.)
+ * Class: org_apache_harmony_luni_platform_OSFileSystem
+ * Method: getAllocGranularity
+ * Signature: ()I
+ */
+static jint harmony_io_getAllocGranularity(JNIEnv * env, jobject thiz) {
+ static int allocGranularity = 0;
+ if(allocGranularity == 0) {
+ allocGranularity = getpagesize();
+ }
+ return allocGranularity;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSFileSystem
+ * Method: readvImpl
+ * Signature: (I[J[I[I)J
+ */
+static jlong harmony_io_readvImpl(JNIEnv *env, jobject thiz, jint fd,
+ jintArray jbuffers, jintArray joffsets, jintArray jlengths, jint size) {
+
+ jboolean bufsCopied = JNI_FALSE;
+ jboolean offsetsCopied = JNI_FALSE;
+ jboolean lengthsCopied = JNI_FALSE;
+ jint *bufs;
+ jint *offsets;
+ jint *lengths;
+ int i = 0;
+ long totalRead = 0;
+ struct iovec *vectors = (struct iovec *)malloc(size * sizeof(struct iovec));
+ if(vectors == NULL) {
+ return -1;
+ }
+ bufs = env->GetIntArrayElements(jbuffers, &bufsCopied);
+ offsets = env->GetIntArrayElements(joffsets, &offsetsCopied);
+ lengths = env->GetIntArrayElements(jlengths, &lengthsCopied);
+ while(i < size) {
+ vectors[i].iov_base = (void *)((int)(bufs[i]+offsets[i]));
+ vectors[i].iov_len = lengths[i];
+ i++;
+ }
+ totalRead = readv(fd, vectors, size);
+ if(bufsCopied) {
+ env->ReleaseIntArrayElements(jbuffers, bufs, JNI_ABORT);
+ }
+ if(offsetsCopied) {
+ env->ReleaseIntArrayElements(joffsets, offsets, JNI_ABORT);
+ }
+ if(lengthsCopied) {
+ env->ReleaseIntArrayElements(jlengths, lengths, JNI_ABORT);
+ }
+ free(vectors);
+ return totalRead;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSFileSystem
+ * Method: writevImpl
+ * Signature: (I[J[I[I)J
+ */
+static jlong harmony_io_writevImpl(JNIEnv *env, jobject thiz, jint fd,
+ jintArray jbuffers, jintArray joffsets, jintArray jlengths, jint size) {
+
+ jboolean bufsCopied = JNI_FALSE;
+ jboolean offsetsCopied = JNI_FALSE;
+ jboolean lengthsCopied = JNI_FALSE;
+ jint *bufs;
+ jint *offsets;
+ jint *lengths;
+ int i = 0;
+ long totalRead = 0;
+ struct iovec *vectors = (struct iovec *)malloc(size * sizeof(struct iovec));
+ if(vectors == NULL) {
+ return -1;
+ }
+ bufs = env->GetIntArrayElements(jbuffers, &bufsCopied);
+ offsets = env->GetIntArrayElements(joffsets, &offsetsCopied);
+ lengths = env->GetIntArrayElements(jlengths, &lengthsCopied);
+ while(i < size) {
+ vectors[i].iov_base = (void *)((int)(bufs[i]+offsets[i]));
+ vectors[i].iov_len = lengths[i];
+ i++;
+ }
+ totalRead = writev(fd, vectors, size);
+ if(bufsCopied) {
+ env->ReleaseIntArrayElements(jbuffers, bufs, JNI_ABORT);
+ }
+ if(offsetsCopied) {
+ env->ReleaseIntArrayElements(joffsets, offsets, JNI_ABORT);
+ }
+ if(lengthsCopied) {
+ env->ReleaseIntArrayElements(jlengths, lengths, JNI_ABORT);
+ }
+ free(vectors);
+ return totalRead;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSFileSystem
+ * Method: transferImpl
+ * Signature: (IJJ)J
+ */
+static jlong harmony_io_transferImpl(JNIEnv *env, jobject thiz, jint fd,
+ jobject sd, jlong offset, jlong count) {
+
+ int socket;
+ off_t off;
+
+ socket = jniGetFDFromFileDescriptor(env, sd);
+ if(socket == 0 || socket == -1) {
+ return -1;
+ }
+
+ /* Value of offset is checked in jint scope (checked in java layer)
+ The conversion here is to guarantee no value lost when converting offset to off_t
+ */
+ off = offset;
+
+ return sendfile(socket,(int)fd,(off_t *)&off,(size_t)count);
+}
+
+/*
+ * Class: org_apache_harmony_io
+ * Method: readDirectImpl
+ * Signature: (IJI)J
+ */
+static jlong harmony_io_readDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+ jint buf, jint offset, jint nbytes) {
+ jint result;
+ if(nbytes == 0) {
+ return (jlong) 0;
+ }
+
+ result = read(fd, (void *) ((jint *)(buf+offset)), (int) nbytes);
+ if(result == 0) {
+ return (jlong) -1;
+ } else {
+ return (jlong) result;
+ }
+}
+
+/*
+ * Class: org_apache_harmony_io
+ * Method: writeDirectImpl
+ * Signature: (IJI)J
+ */
+static jlong harmony_io_writeDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+ jint buf, jint offset, jint nbytes) {
+
+
+ int rc = 0;
+
+ /* write will just do the right thing for HYPORT_TTY_OUT and HYPORT_TTY_ERR */
+ rc = write (fd, (const void *) ((jint *)(buf+offset)), (int) nbytes);
+
+ if(rc == -1) {
+ jniThrowException(env, "java/io/IOException", strerror(errno));
+ return -2;
+ }
+ return (jlong) rc;
+
+}
+
+// BEGIN android-changed
+/*
+ * Class: org_apache_harmony_io
+ * Method: readImpl
+ * Signature: (I[BII)J
+ */
+static jlong harmony_io_readImpl(JNIEnv * env, jobject thiz, jint fd,
+ jbyteArray byteArray, jint offset, jint nbytes) {
+
+ jboolean isCopy;
+ jbyte *bytes;
+ jlong result;
+
+ if (nbytes == 0) {
+ return 0;
+ }
+
+ bytes = env->GetByteArrayElements(byteArray, &isCopy);
+
+ for (;;) {
+ result = read(fd, (void *) (bytes + offset), (int) nbytes);
+
+ if ((result != -1) || (errno != EINTR)) {
+ break;
+ }
+
+ /*
+ * If we didn't break above, that means that the read() call
+ * returned due to EINTR. We shield Java code from this
+ * possibility by trying again. Note that this is different
+ * from EAGAIN, which should result in this code throwing
+ * an InterruptedIOException.
+ */
+ }
+
+ env->ReleaseByteArrayElements(byteArray, bytes, 0);
+
+ if (result == 0) {
+ return -1;
+ }
+
+ if (result == -1) {
+ if (errno == EAGAIN) {
+ jniThrowException(env, "java/io/InterruptedIOException",
+ "Read timed out");
+ } else {
+ jniThrowException(env, "java/io/IOException", strerror(errno));
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Class: org_apache_harmony_io
+ * Method: writeImpl
+ * Signature: (I[BII)J
+ */
+static jlong harmony_io_writeImpl(JNIEnv * env, jobject thiz, jint fd,
+ jbyteArray byteArray, jint offset, jint nbytes) {
+
+ jboolean isCopy;
+ jbyte *bytes = env->GetByteArrayElements(byteArray, &isCopy);
+ jlong result;
+
+ for (;;) {
+ result = write(fd, (const char *) bytes + offset, (int) nbytes);
+
+ if ((result != -1) || (errno != EINTR)) {
+ break;
+ }
+
+ /*
+ * If we didn't break above, that means that the read() call
+ * returned due to EINTR. We shield Java code from this
+ * possibility by trying again. Note that this is different
+ * from EAGAIN, which should result in this code throwing
+ * an InterruptedIOException.
+ */
+ }
+
+ env->ReleaseByteArrayElements(byteArray, bytes, JNI_ABORT);
+
+ if (result == -1) {
+ if (errno == EAGAIN) {
+ jniThrowException(env, "java/io/InterruptedIOException",
+ "Write timed out");
+ } else {
+ jniThrowException(env, "java/io/IOException", strerror(errno));
+ }
+ }
+
+ return result;
+}
+// END android-changed
+
+/**
+ * Seeks a file descriptor to a given file position.
+ *
+ * @param env pointer to Java environment
+ * @param thiz pointer to object receiving the message
+ * @param fd handle of file to be seeked
+ * @param offset distance of movement in bytes relative to whence arg
+ * @param whence enum value indicating from where the offset is relative
+ * The valid values are defined in fsconstants.h.
+ * @return the new file position from the beginning of the file, in bytes;
+ * or -1 if a problem occurs.
+ */
+static jlong harmony_io_seekImpl(JNIEnv * env, jobject thiz, jint fd,
+ jlong offset, jint whence) {
+
+ int mywhence = 0;
+
+ /* Convert whence argument */
+ switch (whence) {
+ case 1:
+ mywhence = 0;
+ break;
+ case 2:
+ mywhence = 1;
+ break;
+ case 4:
+ mywhence = 2;
+ break;
+ default:
+ return -1;
+ }
+
+
+ off_t localOffset = (int) offset;
+
+ if((mywhence < 0) || (mywhence > 2)) {
+ return -1;
+ }
+
+ /* If file offsets are 32 bit, truncate the seek to that range */
+ if(sizeof (off_t) < sizeof (jlong)) {
+ if(offset > 0x7FFFFFFF) {
+ localOffset = 0x7FFFFFFF;
+ } else if(offset < -0x7FFFFFFF) {
+ localOffset = -0x7FFFFFFF;
+ }
+ }
+
+ return (jlong) lseek(fd, localOffset, mywhence);
+}
+
+/**
+ * Flushes a file state to disk.
+ *
+ * @param env pointer to Java environment
+ * @param thiz pointer to object receiving the message
+ * @param fd handle of file to be flushed
+ * @param metadata if true also flush metadata,
+ * otherwise just flush data is possible.
+ * @return zero on success and -1 on failure
+ *
+ * Method: fflushImpl
+ * Signature: (IZ)I
+ */
+static jint harmony_io_fflushImpl(JNIEnv * env, jobject thiz, jint fd,
+ jboolean metadata) {
+ return (jint) fsync(fd);
+}
+
+// BEGIN android-changed
+/**
+ * Closes the given file handle
+ *
+ * @param env pointer to Java environment
+ * @param thiz pointer to object receiving the message
+ * @param fd handle of file to be closed
+ * @return zero on success and -1 on failure
+ *
+ * Class: org_apache_harmony_io
+ * Method: closeImpl
+ * Signature: (I)I
+ */
+static jint harmony_io_closeImpl(JNIEnv * env, jobject thiz, jint fd) {
+ jint result;
+
+ for (;;) {
+ result = (jint) close(fd);
+
+ if ((result != -1) || (errno != EINTR)) {
+ break;
+ }
+
+ /*
+ * If we didn't break above, that means that the close() call
+ * returned due to EINTR. We shield Java code from this
+ * possibility by trying again.
+ */
+ }
+
+ return result;
+}
+// END android-changed
+
+
+/*
+ * Class: org_apache_harmony_io
+ * Method: truncateImpl
+ * Signature: (IJ)I
+ */
+static jint harmony_io_truncateImpl(JNIEnv * env, jobject thiz, jint fd,
+ jlong size) {
+
+ int rc;
+ off_t length = (off_t) size;
+
+ // If file offsets are 32 bit, truncate the newLength to that range
+ if(sizeof (off_t) < sizeof (jlong)) {
+ if(length > 0x7FFFFFFF) {
+ length = 0x7FFFFFFF;
+ } else if(length < -0x7FFFFFFF) {
+ length = -0x7FFFFFFF;
+ }
+ }
+
+ rc = ftruncate((int)fd, length);
+
+ return (jint) rc;
+
+}
+
+/*
+ * Class: org_apache_harmony_io
+ * Method: openImpl
+ * Signature: ([BI)I
+ */
+static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
+ jint jflags) {
+
+ int flags = 0;
+ int mode = 0;
+ jint * portFD;
+ jsize length;
+ char pathCopy[HyMaxPath];
+
+// BEGIN android-changed
+// don't want default permissions to allow global access.
+ switch(jflags) {
+ case 0:
+ flags = HyOpenRead;
+ mode = 0;
+ break;
+ case 1:
+ flags = HyOpenCreate | HyOpenWrite | HyOpenTruncate;
+ mode = 0600;
+ break;
+ case 16:
+ flags = HyOpenRead | HyOpenWrite | HyOpenCreate;
+ mode = 0600;
+ break;
+ case 32:
+ flags = HyOpenRead | HyOpenWrite | HyOpenCreate | HyOpenSync;
+ mode = 0600;
+ break;
+ case 256:
+ flags = HyOpenWrite | HyOpenCreate | HyOpenAppend;
+ mode = 0600;
+ break;
+ }
+// BEGIN android-changed
+
+ flags = EsTranslateOpenFlags(flags);
+
+ length = env->GetArrayLength (path);
+ length = length < HyMaxPath - 1 ? length : HyMaxPath - 1;
+ env->GetByteArrayRegion (path, 0, length, (jbyte *)pathCopy);
+ pathCopy[length] = '\0';
+ convertToPlatform (pathCopy);
+
+ int cc;
+
+ if(pathCopy == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return -1;
+ }
+
+ do {
+ cc = open(pathCopy, flags, mode);
+ } while(cc < 0 && errno == EINTR);
+
+ if(cc < 0 && errno > 0) {
+ cc = -errno;
+ }
+
+ return cc;
+
+
+}
+
+// BEGIN android-deleted
+#if 0
+/*
+ * Answers the number of remaining chars in the stdin.
+ *
+ * Class: org_apache_harmony_io
+ * Method: ttyAvailableImpl
+ * Signature: ()J
+ */
+static jlong harmony_io_ttyAvailableImpl(JNIEnv *env, jobject thiz) {
+
+ int rc;
+ off_t curr, end;
+
+ int avail = 0;
+
+ // when redirected from a file
+ curr = lseek(STDIN_FILENO, 0L, 2); /* don't use tell(), it doesn't exist on all platforms, i.e. linux */
+ if(curr != -1) {
+ end = lseek(STDIN_FILENO, 0L, 4);
+ lseek(STDIN_FILENO, curr, 1);
+ if(end >= curr) {
+ return (jlong) (end - curr);
+ }
+ }
+
+ /* ioctl doesn't work for files on all platforms (i.e. SOLARIS) */
+
+ rc = ioctl (STDIN_FILENO, FIONREAD, &avail);
+
+ /* 64 bit platforms use a 32 bit value, using IDATA fails on big endian */
+ /* Pass in IDATA because ioctl() is device dependent, some devices may write 64 bits */
+ if(rc != -1) {
+ return (jlong) *(jint *) & avail;
+ }
+ return (jlong) 0;
+}
+#endif
+// END android-deleted
+
+// BEGIN android-added
+/*
+ * Answers the number of remaining bytes in a file descriptor
+ * using IOCTL.
+ *
+ * Class: org_apache_harmony_io
+ * Method: ioctlAvailable
+ * Signature: ()I
+ */
+static jint harmony_io_ioctlAvailable(JNIEnv *env, jobject thiz, jint fd) {
+ int avail = 0;
+ int rc = ioctl(fd, FIONREAD, &avail);
+
+ /*
+ * On underlying platforms Android cares about (read "Linux"),
+ * ioctl(fd, FIONREAD, &avail) is supposed to do the following:
+ *
+ * If the fd refers to a regular file, avail is set to
+ * the difference between the file size and the current cursor.
+ * This may be negative if the cursor is past the end of the file.
+ *
+ * If the fd refers to an open socket or the read end of a
+ * pipe, then avail will be set to a number of bytes that are
+ * available to be read without blocking.
+ *
+ * If the fd refers to a special file/device that has some concept
+ * of buffering, then avail will be set in a corresponding way.
+ *
+ * If the fd refers to a special device that does not have any
+ * concept of buffering, then the ioctl call will return a negative
+ * number, and errno will be set to ENOTTY.
+ *
+ * If the fd refers to a special file masquerading as a regular file,
+ * then avail may be returned as negative, in that the special file
+ * may appear to have zero size and yet a previous read call may have
+ * actually read some amount of data and caused the cursor to be
+ * advanced.
+ */
+
+ if (rc >= 0) {
+ /*
+ * Success, but make sure not to return a negative number (see
+ * above).
+ */
+ if (avail < 0) {
+ avail = 0;
+ }
+ } else if (errno == ENOTTY) {
+ /* The fd is unwilling to opine about its read buffer. */
+ avail = 0;
+ } else {
+ /* Something strange is happening. */
+ jniThrowException(env, "java/io/IOException", strerror(errno));
+ avail = 0;
+ }
+
+ return (jint) avail;
+}
+// END android-added
+
+/*
+ * Reads the number of bytes from stdin.
+ *
+ * Class: org_apache_harmony_io
+ * Method: ttyReadImpl
+ * Signature: ([BII)J
+ */
+static jlong harmony_io_ttyReadImpl(JNIEnv *env, jobject thiz,
+ jbyteArray byteArray, jint offset, jint nbytes) {
+
+ jboolean isCopy;
+ jbyte *bytes = env->GetByteArrayElements(byteArray, &isCopy);
+ jlong result;
+
+ for(;;) {
+
+ result = (jlong) read(STDIN_FILENO, (char *)(bytes + offset), (int) nbytes);
+
+ if ((result != -1) || (errno != EINTR)) {
+ break;
+ }
+
+ /*
+ * If we didn't break above, that means that the read() call
+ * returned due to EINTR. We shield Java code from this
+ * possibility by trying again. Note that this is different
+ * from EAGAIN, which should result in this code throwing
+ * an InterruptedIOException.
+ */
+ }
+
+ env->ReleaseByteArrayElements(byteArray, bytes, 0);
+
+ if (result == 0) {
+ return -1;
+ }
+
+ if (result == -1) {
+ if (errno == EAGAIN) {
+ jniThrowException(env, "java/io/InterruptedIOException",
+ "Read timed out");
+ } else {
+ jniThrowException(env, "java/io/IOException", strerror(errno));
+ }
+ }
+
+ return result;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "lockImpl", "(IJJIZ)I", (void*) harmony_io_lockImpl },
+ { "getAllocGranularity","()I", (void*) harmony_io_getAllocGranularity },
+ { "unlockImpl", "(IJJ)I", (void*) harmony_io_unlockImpl },
+ { "fflushImpl", "(IZ)I", (void*) harmony_io_fflushImpl },
+ { "seekImpl", "(IJI)J", (void*) harmony_io_seekImpl },
+ { "readDirectImpl", "(IIII)J", (void*) harmony_io_readDirectImpl },
+ { "writeDirectImpl", "(IIII)J", (void*) harmony_io_writeDirectImpl },
+ { "readImpl", "(I[BII)J", (void*) harmony_io_readImpl },
+ { "writeImpl", "(I[BII)J", (void*) harmony_io_writeImpl },
+ { "readvImpl", "(I[I[I[II)J",(void*) harmony_io_readvImpl },
+ { "writevImpl", "(I[I[I[II)J",(void*) harmony_io_writevImpl },
+ { "closeImpl", "(I)I", (void*) harmony_io_closeImpl },
+ { "truncateImpl", "(IJ)I", (void*) harmony_io_truncateImpl },
+ { "openImpl", "([BI)I", (void*) harmony_io_openImpl },
+ { "transferImpl", "(ILjava/io/FileDescriptor;JJ)J",
+ (void*) harmony_io_transferImpl },
+ // BEGIN android-deleted
+ //{ "ttyAvailableImpl", "()J", (void*) harmony_io_ttyAvailableImpl },
+ // END android-deleted
+ // BEGIN android-added
+ { "ioctlAvailable", "(I)I", (void*) harmony_io_ioctlAvailable },
+ // END android added
+ { "ttyReadImpl", "([BII)J", (void*) harmony_io_ttyReadImpl }
+};
+int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv *_env) {
+ return jniRegisterNativeMethods(_env,
+ "org/apache/harmony/luni/platform/OSFileSystem", gMethods,
+ NELEM(gMethods));
+}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
new file mode 100644
index 0000000..5bd7907
--- /dev/null
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "utils/misc.h"
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#undef MMAP_READ_ONLY
+#define MMAP_READ_ONLY 1L
+#undef MMAP_READ_WRITE
+#define MMAP_READ_WRITE 2L
+#undef MMAP_WRITE_COPY
+#define MMAP_WRITE_COPY 4L
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: littleEndian
+ * Signature: ()Z
+ */
+static jboolean harmony_nio_littleEndian(JNIEnv *_env, jclass _this) {
+ long l = 0x01020304;
+ unsigned char* c = (unsigned char*)&l;
+ return (*c == 0x04) ? JNI_TRUE : JNI_FALSE;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getPointerSizeImpl
+ * Signature: ()I
+ */
+static jint harmony_nio_getPointerSizeImpl(JNIEnv *_env, jclass _this) {
+ return sizeof(void *);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: mallocImpl
+ * Signature: (I)I
+ */
+static jint harmony_nio_mallocImpl(JNIEnv *_env, jobject _this, jint size) {
+ void *returnValue = malloc(size);
+ if(returnValue == NULL) {
+ jniThrowException(_env, "java.lang.OutOfMemoryError", "");
+ }
+ return (jint)returnValue;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: freeImpl
+ * Signature: (I)V
+ */
+static void harmony_nio_freeImpl(JNIEnv *_env, jobject _this, jint pointer) {
+ free((void *)pointer);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: memset
+ * Signature: (IBJ)V
+ */
+static void harmony_nio_memset(JNIEnv *_env, jobject _this, jint address,
+ jbyte value, jlong length) {
+ memset ((void *) ((jint) address), (jbyte) value, (jlong) length);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: memmove
+ * Signature: (IIJ)V
+ */
+static void harmony_nio_memmove(JNIEnv *_env, jobject _this, jint destAddress,
+ jint srcAddress, jlong length) {
+ memmove ((void *) ((jint) destAddress), (const void *) ((jint) srcAddress),
+ (jlong) length);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getByteImpl
+ * Signature: (I)B
+ */
+static jbyte harmony_nio_getByteImpl(JNIEnv *_env, jobject _this,
+ jint pointer) {
+ jbyte returnValue = *((jbyte *)pointer);
+ return returnValue;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getBytesImpl
+ * Signature: (I[BII)V
+ */
+static void harmony_nio_getBytesImpl(JNIEnv *_env, jobject _this, jint pointer,
+ jbyteArray dst, jint offset, jint length) {
+ jbyte *dst_ = (jbyte *)_env->GetPrimitiveArrayCritical(dst, (jboolean *)0);
+ memcpy(dst_ + offset, (jbyte *)pointer, length);
+ _env->ReleasePrimitiveArrayCritical(dst, dst_, 0);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: putByteImpl
+ * Signature: (IB)V
+ */
+static void harmony_nio_putByteImpl(JNIEnv *_env, jobject _this, jint pointer,
+ jbyte val) {
+ *((jbyte *)pointer) = val;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: putBytesImpl
+ * Signature: (I[BII)V
+ */
+static void harmony_nio_putBytesImpl(JNIEnv *_env, jobject _this,
+ jint pointer, jbyteArray src, jint offset, jint length) {
+ jbyte *src_ = (jbyte *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0);
+ memcpy((jbyte *)pointer, src_ + offset, length);
+ _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT);
+}
+
+static void
+swapShorts(jshort *shorts, int numBytes) {
+ jbyte *src = (jbyte *) shorts;
+ jbyte *dst = src;
+ int i;
+
+ for (i = 0; i < numBytes; i+=2) {
+ jbyte b0 = *src++;
+ jbyte b1 = *src++;
+ *dst++ = b1;
+ *dst++ = b0;
+ }
+}
+
+static void
+swapInts(jint *ints, int numBytes) {
+ jbyte *src = (jbyte *) ints;
+ jbyte *dst = src;
+ int i;
+ for (i = 0; i < numBytes; i+=4) {
+ jbyte b0 = *src++;
+ jbyte b1 = *src++;
+ jbyte b2 = *src++;
+ jbyte b3 = *src++;
+ *dst++ = b3;
+ *dst++ = b2;
+ *dst++ = b1;
+ *dst++ = b0;
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: putShortsImpl
+ * Signature: (I[SIIZ)V
+ */
+static void harmony_nio_putShortsImpl(JNIEnv *_env, jobject _this,
+ jint pointer, jshortArray src, jint offset, jint length, jboolean swap) {
+
+ offset = offset << 1;
+ length = length << 1;
+
+ jshort *src_ =
+ (jshort *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0);
+ if (swap) {
+ swapShorts(src_ + offset, length);
+ }
+ memcpy((jbyte *)pointer, src_ + offset, length);
+ if (swap) {
+ swapShorts(src_ + offset, length);
+ }
+ _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: putIntsImpl
+ * Signature: (I[IIIZ)V
+ */
+static void harmony_nio_putIntsImpl(JNIEnv *_env, jobject _this,
+ jint pointer, jintArray src, jint offset, jint length, jboolean swap) {
+
+ offset = offset << 2;
+ length = length << 2;
+
+ jint *src_ =
+ (jint *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0);
+ if (swap) {
+ swapInts(src_ + offset, length);
+ }
+ memcpy((jbyte *)pointer, src_ + offset, length);
+ if (swap) {
+ swapInts(src_ + offset, length);
+ }
+ _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getShortImpl
+ * Signature: (I)S
+ */
+static jshort harmony_nio_getShortImpl(JNIEnv *_env, jobject _this,
+ jint pointer) {
+ if ((pointer & 0x1) == 0) {
+ jshort returnValue = *((jshort *)pointer);
+ return returnValue;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ jshort s;
+ unsigned char *src = (unsigned char *) pointer;
+ unsigned char *dst = (unsigned char *) &s;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ return s;
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: petShortImpl
+ * Signature: (IS)V
+ */
+static void harmony_nio_putShortImpl(JNIEnv *_env, jobject _this, jint pointer,
+ jshort value) {
+ if ((pointer & 0x1) == 0) {
+ *((jshort *)pointer) = value;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ unsigned char *src = (unsigned char *) &value;
+ unsigned char *dst = (unsigned char *) pointer;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getIntImpl
+ * Signature: (I)I
+ */
+static jint harmony_nio_getIntImpl(JNIEnv *_env, jobject _this, jint pointer) {
+ if ((pointer & 0x3) == 0) {
+ jint returnValue = *((jint *)pointer);
+ return returnValue;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ jint i;
+ unsigned char *src = (unsigned char *) pointer;
+ unsigned char *dst = (unsigned char *) &i;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ return i;
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: putIntImpl
+ * Signature: (II)V
+ */
+static void harmony_nio_putIntImpl(JNIEnv *_env, jobject _this, jint pointer,
+ jint value) {
+ if ((pointer & 0x3) == 0) {
+ *((jint *)pointer) = value;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ unsigned char *src = (unsigned char *) &value;
+ unsigned char *dst = (unsigned char *) pointer;
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getLongImpl
+ * Signature: (I)Ljava/lang/Long;
+ */
+static jlong harmony_nio_getLongImpl(JNIEnv *_env, jobject _this,
+ jint pointer) {
+ if ((pointer & 0x7) == 0) {
+ jlong returnValue = *((jlong *)pointer);
+ return returnValue;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ jlong l;
+ memcpy((void *) &l, (void *) pointer, sizeof(jlong));
+ return l;
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: putLongImpl
+ * Signature: (IJ)V
+ */
+static void harmony_nio_putLongImpl(JNIEnv *_env, jobject _this, jint pointer,
+ jlong value) {
+ if ((pointer & 0x7) == 0) {
+ *((jlong *)pointer) = value;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ memcpy((void *) pointer, (void *) &value, sizeof(jlong));
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getFloatImpl
+ * Signature: (I)F
+ */
+static jfloat harmony_nio_getFloatImpl(JNIEnv *_env, jobject _this,
+ jint pointer) {
+ if ((pointer & 0x3) == 0) {
+ jfloat returnValue = *((jfloat *)pointer);
+ return returnValue;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ jfloat f;
+ memcpy((void *) &f, (void *) pointer, sizeof(jfloat));
+ return f;
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: setFloatImpl
+ * Signature: (IF)V
+ */
+static void harmony_nio_putFloatImpl(JNIEnv *_env, jobject _this, jint pointer,
+ jfloat value) {
+ if ((pointer & 0x3) == 0) {
+ *((jfloat *)pointer) = value;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ memcpy((void *) pointer, (void *) &value, sizeof(jfloat));
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getDoubleImpl
+ * Signature: (I)D
+ */
+static jdouble harmony_nio_getDoubleImpl(JNIEnv *_env, jobject _this,
+ jint pointer) {
+ if ((pointer & 0x7) == 0) {
+ jdouble returnValue = *((jdouble *)pointer);
+ return returnValue;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ jdouble d;
+ memcpy((void *) &d, (void *) pointer, sizeof(jdouble));
+ return d;
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: putDoubleImpl
+ * Signature: (ID)V
+ */
+static void harmony_nio_putDoubleImpl(JNIEnv *_env, jobject _this, jint pointer,
+ jdouble value) {
+ if ((pointer & 0x7) == 0) {
+ *((jdouble *)pointer) = value;
+ } else {
+ // Handle unaligned memory access one byte at a time
+ memcpy((void *) pointer, (void *) &value, sizeof(jdouble));
+ }
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: getAddress
+ * Signature: (I)I
+ */
+static jint harmony_nio_getAddress(JNIEnv *_env, jobject _this, jint pointer) {
+ return (jint) * (int *) pointer;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: setAddress
+ * Signature: (II)V
+ */
+static void harmony_nio_setAddress(JNIEnv *_env, jobject _this, jint pointer,
+ jint value) {
+ *(int *) pointer = (int) value;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: mmapImpl
+ * Signature: (IJJI)I
+ */
+static jint harmony_nio_mmapImpl(JNIEnv *_env, jobject _this, jint fd,
+ jlong alignment, jlong size, jint mmode) {
+ void *mapAddress = NULL;
+ int prot, flags;
+
+ // Convert from Java mapping mode to port library mapping mode.
+ switch (mmode) {
+ case MMAP_READ_ONLY:
+ prot = PROT_READ;
+ flags = MAP_SHARED;
+ break;
+ case MMAP_READ_WRITE:
+ prot = PROT_READ|PROT_WRITE;
+ flags = MAP_SHARED;
+ break;
+ case MMAP_WRITE_COPY:
+ prot = PROT_READ|PROT_WRITE;
+ flags = MAP_PRIVATE;
+ break;
+ default:
+ return -1;
+ }
+
+ mapAddress = mmap(0, (size_t)(size&0x7fffffff), prot, flags,fd,
+ (off_t)(alignment&0x7fffffff));
+ if (mapAddress == MAP_FAILED) {
+ return -1;
+ }
+
+ return (jint) mapAddress;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: unmapImpl
+ * Signature: (IJ)V
+ */
+static void harmony_nio_unmapImpl(JNIEnv *_env, jobject _this, jint address,
+ jlong size) {
+ munmap((void *)address, (size_t)size);
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: loadImpl
+ * Signature: (IJ)I
+ */
+static jint harmony_nio_loadImpl(JNIEnv *_env, jobject _this, jint address,
+ jlong size) {
+
+ if(mlock((void *)address, (size_t)size)!=-1) {
+ if(munlock((void *)address, (size_t)size)!=-1) {
+ return 0; /* normally */
+ }
+ }
+ else {
+ /* according to linux sys call, only root can mlock memory. */
+ if(errno == EPERM) {
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int getPageSize() {
+ static int page_size = 0;
+ if(page_size==0)
+ {
+ page_size=getpagesize();
+ }
+ return page_size;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: isLoadedImpl
+ * Signature: (IJ)Z
+ */
+static jboolean harmony_nio_isLoadedImpl(JNIEnv *_env, jobject _this,
+ jint address, jlong size) {
+
+ jboolean result = 0;
+ jint m_addr = (jint)address;
+ int page_size = getPageSize();
+ unsigned char* vec = NULL;
+ int page_count = 0;
+
+ int align_offset = m_addr%page_size;// addr should align with the boundary of a page.
+ m_addr -= align_offset;
+ size += align_offset;
+ page_count = (size+page_size-1)/page_size;
+
+ vec = (unsigned char *) malloc(page_count*sizeof(char));
+
+ if (mincore((void *)m_addr, size, (MINCORE_POINTER_TYPE) vec)==0) {
+ // or else there is error about the mincore and return false;
+ int i;
+ for(i=0 ;i<page_count;i++) {
+ if(vec[i]!=1) {
+ break;
+ }
+ }
+ if(i==page_count) {
+ result = 1;
+ }
+ }
+
+ free(vec);
+
+ return result;
+}
+
+/*
+ * Class: org_apache_harmony_luni_platform_OSMemory
+ * Method: flushImpl
+ * Signature: (IJ)I
+ */
+static jint harmony_nio_flushImpl(JNIEnv *_env, jobject _this, jint address,
+ jlong size) {
+ return msync((void *)address, size, MS_SYNC);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "isLittleEndianImpl", "()Z", (void*) harmony_nio_littleEndian },
+ { "getPointerSizeImpl", "()I", (void*) harmony_nio_getPointerSizeImpl },
+ { "malloc", "(I)I", (void*) harmony_nio_mallocImpl },
+ { "free", "(I)V", (void*) harmony_nio_freeImpl },
+ { "memset", "(IBJ)V", (void*) harmony_nio_memset },
+ { "memmove", "(IIJ)V", (void*) harmony_nio_memmove },
+ { "getByteArray", "(I[BII)V",(void*) harmony_nio_getBytesImpl },
+ { "setByteArray", "(I[BII)V",(void*) harmony_nio_putBytesImpl },
+ { "setShortArray", "(I[SIIZ)V",(void*) harmony_nio_putShortsImpl },
+ { "setIntArray", "(I[IIIZ)V",(void*) harmony_nio_putIntsImpl },
+ { "getByte", "(I)B", (void*) harmony_nio_getByteImpl },
+ { "setByte", "(IB)V", (void*) harmony_nio_putByteImpl },
+ { "getShort", "(I)S", (void*) harmony_nio_getShortImpl },
+ { "setShort", "(IS)V", (void*) harmony_nio_putShortImpl },
+ { "getInt", "(I)I", (void*) harmony_nio_getIntImpl },
+ { "setInt", "(II)V", (void*) harmony_nio_putIntImpl },
+ { "getLong", "(I)J", (void*) harmony_nio_getLongImpl },
+ { "setLong", "(IJ)V", (void*) harmony_nio_putLongImpl },
+ { "getFloat", "(I)F", (void*) harmony_nio_getFloatImpl },
+ { "setFloat", "(IF)V", (void*) harmony_nio_putFloatImpl },
+ { "getDouble", "(I)D", (void*) harmony_nio_getDoubleImpl },
+ { "setDouble", "(ID)V", (void*) harmony_nio_putDoubleImpl },
+ { "getAddress", "(I)I", (void*) harmony_nio_getAddress },
+ { "setAddress", "(II)V", (void*) harmony_nio_setAddress },
+ { "mmapImpl", "(IJJI)I", (void*) harmony_nio_mmapImpl },
+ { "unmapImpl", "(IJ)V", (void*) harmony_nio_unmapImpl },
+ { "loadImpl", "(IJ)I", (void*) harmony_nio_loadImpl },
+ { "isLoadedImpl", "(IJ)Z", (void*) harmony_nio_isLoadedImpl },
+ { "flushImpl", "(IJ)I", (void*) harmony_nio_flushImpl }
+};
+int register_org_apache_harmony_luni_platform_OSMemory(JNIEnv *_env) {
+ return jniRegisterNativeMethods(_env, "org/apache/harmony/luni/platform/OSMemory",
+ gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
new file mode 100755
index 0000000..de01295
--- /dev/null
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -0,0 +1,3637 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OSNetworkSystem"
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "errno.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+
+#include <cutils/properties.h>
+#include <cutils/adb_networking.h>
+#include <utils/LogSocket.h>
+#include "AndroidSystemNatives.h"
+
+/**
+ * @name Socket Errors
+ * Error codes for socket operations
+ *
+ * @internal SOCKERR* range from -200 to -299 avoid overlap
+ */
+#define SOCKERR_BADSOCKET -200 /* generic error */
+#define SOCKERR_NOTINITIALIZED -201 /* socket library uninitialized */
+#define SOCKERR_BADAF -202 /* bad address family */
+#define SOCKERR_BADPROTO -203 /* bad protocol */
+#define SOCKERR_BADTYPE -204 /* bad type */
+#define SOCKERR_SYSTEMBUSY -205 /* system busy handling requests */
+#define SOCKERR_SYSTEMFULL -206 /* too many sockets */
+#define SOCKERR_NOTCONNECTED -207 /* socket is not connected */
+#define SOCKERR_INTERRUPTED -208 /* the call was cancelled */
+#define SOCKERR_TIMEOUT -209 /* the operation timed out */
+#define SOCKERR_CONNRESET -210 /* the connection was reset */
+#define SOCKERR_WOULDBLOCK -211 /* the socket is marked as nonblocking operation would block */
+#define SOCKERR_ADDRNOTAVAIL -212 /* address not available */
+#define SOCKERR_ADDRINUSE -213 /* address already in use */
+#define SOCKERR_NOTBOUND -214 /* the socket is not bound */
+#define SOCKERR_UNKNOWNSOCKET -215 /* resolution of fileDescriptor to socket failed */
+#define SOCKERR_INVALIDTIMEOUT -216 /* the specified timeout is invalid */
+#define SOCKERR_FDSETFULL -217 /* Unable to create an FDSET */
+#define SOCKERR_TIMEVALFULL -218 /* Unable to create a TIMEVAL */
+#define SOCKERR_REMSOCKSHUTDOWN -219 /* The remote socket has shutdown gracefully */
+#define SOCKERR_NOTLISTENING -220 /* listen() was not invoked prior to accept() */
+#define SOCKERR_NOTSTREAMSOCK -221 /* The socket does not support connection-oriented service */
+#define SOCKERR_ALREADYBOUND -222 /* The socket is already bound to an address */
+#define SOCKERR_NBWITHLINGER -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
+#define SOCKERR_ISCONNECTED -224 /* The socket is already connected */
+#define SOCKERR_NOBUFFERS -225 /* No buffer space is available */
+#define SOCKERR_HOSTNOTFOUND -226 /* Authoritative Answer Host not found */
+#define SOCKERR_NODATA -227 /* Valid name, no data record of requested type */
+#define SOCKERR_BOUNDORCONN -228 /* The socket has not been bound or is already connected */
+#define SOCKERR_OPNOTSUPP -229 /* The socket does not support the operation */
+#define SOCKERR_OPTUNSUPP -230 /* The socket option is not supported */
+#define SOCKERR_OPTARGSINVALID -231 /* The socket option arguments are invalid */
+#define SOCKERR_SOCKLEVELINVALID -232 /* The socket level is invalid */
+#define SOCKERR_TIMEOUTFAILURE -233
+#define SOCKERR_SOCKADDRALLOCFAIL -234 /* Unable to allocate the sockaddr structure */
+#define SOCKERR_FDSET_SIZEBAD -235 /* The calculated maximum size of the file descriptor set is bad */
+#define SOCKERR_UNKNOWNFLAG -236 /* The flag is unknown */
+#define SOCKERR_MSGSIZE -237 /* The datagram was too big to fit the specified buffer & was truncated. */
+#define SOCKERR_NORECOVERY -238 /* The operation failed with no recovery possible */
+#define SOCKERR_ARGSINVALID -239 /* The arguments are invalid */
+#define SOCKERR_BADDESC -240 /* The socket argument is not a valid file descriptor */
+#define SOCKERR_NOTSOCK -241 /* The socket argument is not a socket */
+#define SOCKERR_HOSTENTALLOCFAIL -242 /* Unable to allocate the hostent structure */
+#define SOCKERR_TIMEVALALLOCFAIL -243 /* Unable to allocate the timeval structure */
+#define SOCKERR_LINGERALLOCFAIL -244 /* Unable to allocate the linger structure */
+#define SOCKERR_IPMREQALLOCFAIL -245 /* Unable to allocate the ipmreq structure */
+#define SOCKERR_FDSETALLOCFAIL -246 /* Unable to allocate the fdset structure */
+#define SOCKERR_OPFAILED -247 /* Operation failed */
+#define SOCKERR_VALUE_NULL -248 /* The value indexed was NULL */
+#define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
+#define SOCKERR_ENETUNREACH -250 /* network is not reachable */
+#define SOCKERR_EACCES -251 /* permissions do not allow action on socket */
+#define SOCKERR_EHOSTUNREACH -252 /* no route to host */
+#define SOCKERR_EPIPE -253 /* broken pipe */
+
+#define JAVASOCKOPT_TCP_NODELAY 1
+#define JAVASOCKOPT_IP_TOS 3
+#define JAVASOCKOPT_SO_REUSEADDR 4
+#define JAVASOCKOPT_SO_KEEPALIVE 8
+#define JAVASOCKOPT_MCAST_TIME_TO_LIVE 10 /* Currently unused */
+#define JAVASOCKOPT_SO_BINDADDR 15
+#define JAVASOCKOPT_MCAST_INTERFACE 16
+#define JAVASOCKOPT_MCAST_TTL 17
+#define JAVASOCKOPT_IP_MULTICAST_LOOP 18
+#define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
+#define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
+#define JAVASOCKOPT_IP_MULTICAST_IF2 31
+#define JAVASOCKOPT_SO_BROADCAST 32
+#define JAVASOCKOPT_SO_LINGER 128
+#define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT 10001
+#define JAVASOCKOPT_SO_SNDBUF 4097
+#define JAVASOCKOPT_SO_RCVBUF 4098
+#define JAVASOCKOPT_SO_RCVTIMEOUT 4102
+#define JAVASOCKOPT_SO_OOBINLINE 4099
+
+/* constants for calling multi-call functions */
+#define SOCKET_STEP_START 10
+#define SOCKET_STEP_CHECK 20
+#define SOCKET_STEP_DONE 30
+
+#define BROKEN_MULTICAST_IF 1
+#define BROKEN_MULTICAST_TTL 2
+#define BROKEN_TCP_NODELAY 4
+
+#define SOCKET_CONNECT_STEP_START 0
+#define SOCKET_CONNECT_STEP_CHECK 1
+
+#define SOCKET_OP_NONE 0
+#define SOCKET_OP_READ 1
+#define SOCKET_OP_WRITE 2
+#define SOCKET_READ_WRITE 3
+
+#define SOCKET_MSG_PEEK 1
+#define SOCKET_MSG_OOB 2
+
+#define SOCKET_NOFLAGS 0
+
+#undef BUFFERSIZE
+#define BUFFERSIZE 2048
+
+// wait for 500000 usec = 0.5 second
+#define SEND_RETRY_TIME 500000
+
+
+struct CachedFields {
+ jfieldID fd_descriptor;
+ jclass iaddr_class;
+ jmethodID iaddr_class_init;
+ jmethodID iaddr_getbyaddress;
+ jfieldID iaddr_ipaddress;
+ jclass genericipmreq_class;
+ jclass integer_class;
+ jmethodID integer_class_init;
+ jfieldID integer_class_value;
+ jclass boolean_class;
+ jmethodID boolean_class_init;
+ jfieldID boolean_class_value;
+ jclass byte_class;
+ jmethodID byte_class_init;
+ jfieldID byte_class_value;
+ jclass string_class;
+ jmethodID string_class_init;
+ jfieldID socketimpl_address;
+ jfieldID socketimpl_port;
+ jclass dpack_class;
+ jfieldID dpack_address;
+ jfieldID dpack_port;
+ jfieldID dpack_length;
+} gCachedFields;
+
+static int useAdbNetworking = 0;
+
+/* needed for connecting with timeout */
+typedef struct selectFDSet {
+ int nfds;
+ int sock;
+ fd_set writeSet;
+ fd_set readSet;
+ fd_set exceptionSet;
+} selectFDSet;
+
+static const char * netLookupErrorString(int anErrorNum);
+
+/**
+ * Throws an SocketException with the message affiliated with the errorCode.
+ */
+static void throwSocketException(JNIEnv *env, int errorCode) {
+ jniThrowException(env, "java/net/SocketException",
+ netLookupErrorString(errorCode));
+}
+
+/**
+ * Throws an IOException with the given message.
+ */
+static void throwIOExceptionStr(JNIEnv *env, const char *message) {
+ jniThrowException(env, "java/io/IOException", message);
+}
+
+/**
+ * Throws a NullPointerException.
+ */
+static void throwNullPointerException(JNIEnv *env) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+}
+
+/**
+ * Converts a 4-byte array to a native address structure. Throws a
+ * NullPointerException or an IOException in case of error. This is
+ * signaled by a return value of -1. The normal return value is 0.
+ */
+static int javaAddressToStructIn(
+ JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
+
+ memset(address, 0, sizeof(address));
+
+ if (java_address == NULL) {
+ return -1;
+ }
+
+ if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
+ return -1;
+ }
+
+ jbyte * java_address_bytes
+ = env->GetByteArrayElements(java_address, NULL);
+
+ memcpy(&(address->s_addr),
+ java_address_bytes,
+ sizeof(address->s_addr));
+
+ env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
+
+ return 0;
+}
+
+/**
+ * Converts a native address structure to a 4-byte array. Throws a
+ * NullPointerException or an IOException in case of error. This is
+ * signaled by a return value of -1. The normal return value is 0.
+ */
+static int structInToJavaAddress(
+ JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
+
+ if (java_address == NULL) {
+ return -1;
+ }
+
+ if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
+ return -1;
+ }
+
+ jbyte *java_address_bytes;
+
+ java_address_bytes = env->GetByteArrayElements(java_address, NULL);
+
+ memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
+
+ env->ReleaseByteArrayElements(java_address, java_address_bytes, 0);
+
+ return 0;
+}
+
+/**
+ * Converts a native address structure to an InetAddress object.
+ * Throws a NullPointerException or an IOException in case of
+ * error. This is signaled by a return value of -1. The normal
+ * return value is 0.
+ */
+static int socketAddressToInetAddress(JNIEnv *env,
+ struct sockaddr_in *sockaddress, jobject inetaddress, int *port) {
+
+ jbyteArray ipaddress;
+ int result;
+
+ ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+ gCachedFields.iaddr_ipaddress);
+
+ if (structInToJavaAddress(env, &sockaddress->sin_addr, ipaddress) < 0) {
+ return -1;
+ }
+
+ *port = ntohs(sockaddress->sin_port);
+
+ return 0;
+}
+
+/**
+ * Converts an InetAddress object to a native address structure.
+ * Throws a NullPointerException or an IOException in case of
+ * error. This is signaled by a return value of -1. The normal
+ * return value is 0.
+ */
+static int inetAddressToSocketAddress(JNIEnv *env,
+ jobject inetaddress, int port, struct sockaddr_in *sockaddress) {
+
+ jbyteArray ipaddress;
+ int result;
+
+ ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+ gCachedFields.iaddr_ipaddress);
+
+ memset(sockaddress, 0, sizeof(sockaddress));
+
+ sockaddress->sin_family = AF_INET;
+ sockaddress->sin_port = htons(port);
+
+ if (javaAddressToStructIn(env, ipaddress, &(sockaddress->sin_addr)) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
+ jbyteArray bytes;
+ int success;
+
+ bytes = env->NewByteArray(4);
+
+ if (bytes == NULL) {
+ return NULL;
+ }
+
+ if (structInToJavaAddress(env, address, bytes) < 0) {
+ return NULL;
+ }
+
+ return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_getbyaddress, bytes);
+}
+
+/**
+ * Answer a new java.lang.Boolean object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the Boolean constructor argument
+ *
+ * @return the new Boolean
+ */
+
+jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.boolean_class;
+ tempMethod = gCachedFields.boolean_class_init;
+ return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
+}
+
+/**
+ * Answer a new java.lang.Byte object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the Byte constructor argument
+ *
+ * @return the new Byte
+ */
+
+jobject newJavaLangByte(JNIEnv * env, jbyte val) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.byte_class;
+ tempMethod = gCachedFields.byte_class_init;
+ return env->NewObject(tempClass, tempMethod, val);
+}
+
+/**
+ * Answer a new java.lang.Integer object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the Integer constructor argument
+ *
+ * @return the new Integer
+ */
+
+jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.integer_class;
+ tempMethod = gCachedFields.integer_class_init;
+ return env->NewObject(tempClass, tempMethod, anInt);
+}
+
+/**
+ * Answer a new java.lang.String object.
+ *
+ * @param env pointer to the JNI library
+ * @param anInt the byte[] constructor argument
+ *
+ * @return the new String
+ */
+
+jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
+ jclass tempClass;
+ jmethodID tempMethod;
+
+ tempClass = gCachedFields.string_class;
+ tempMethod = gCachedFields.string_class_init;
+ return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
+}
+
+/**
+ * Query OS for timestamp.
+ * Retrieve the current value of system clock and convert to milliseconds.
+ *
+ * @param[in] portLibrary The port library.
+ *
+ * @return 0 on failure, time value in milliseconds on success.
+ * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
+ *
+ * technically, this should return I_64 since both timeval.tv_sec and
+ * timeval.tv_usec are long
+ */
+
+static int time_msec_clock() {
+ struct timeval tp;
+ struct timezone tzp;
+
+ gettimeofday(&tp, &tzp);
+ return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+}
+
+/**
+ * check if the passed sockaddr_in struct contains a localhost address
+ *
+ * @param[in] address pointer to the address to check
+ *
+ * @return 0 if the passed address isn't a localhost address
+ */
+static int isLocalhost(struct sockaddr_in *address) {
+ // return address == 127.0.0.1
+ return (unsigned int) address->sin_addr.s_addr == 16777343;
+}
+
+/**
+ * Answer the errorString corresponding to the errorNumber, if available.
+ * This function will answer a default error string, if the errorNumber is not
+ * recognized.
+ *
+ * This function will have to be reworked to handle internationalization
+ * properly, removing the explicit strings.
+ *
+ * @param anErrorNum the error code to resolve to a human readable string
+ *
+ * @return a human readable error string
+ */
+
+static const char * netLookupErrorString(int anErrorNum) {
+ switch (anErrorNum) {
+ case SOCKERR_BADSOCKET:
+ return "Bad socket";
+ case SOCKERR_NOTINITIALIZED:
+ return "Socket library uninitialized";
+ case SOCKERR_BADAF:
+ return "Bad address family";
+ case SOCKERR_BADPROTO:
+ return "Bad protocol";
+ case SOCKERR_BADTYPE:
+ return "Bad type";
+ case SOCKERR_SYSTEMBUSY:
+ return "System busy handling requests";
+ case SOCKERR_SYSTEMFULL:
+ return "Too many sockets allocated";
+ case SOCKERR_NOTCONNECTED:
+ return "Socket is not connected";
+ case SOCKERR_INTERRUPTED:
+ return "The system call was cancelled";
+ case SOCKERR_TIMEOUT:
+ return "The operation timed out";
+ case SOCKERR_CONNRESET:
+ return "The connection was reset";
+ case SOCKERR_WOULDBLOCK:
+ return "The nonblocking operation would block";
+ case SOCKERR_ADDRNOTAVAIL:
+ return "The address is not available";
+ case SOCKERR_ADDRINUSE:
+ return "The address is already in use";
+ case SOCKERR_NOTBOUND:
+ return "The socket is not bound";
+ case SOCKERR_UNKNOWNSOCKET:
+ return "Resolution of the FileDescriptor to socket failed";
+ case SOCKERR_INVALIDTIMEOUT:
+ return "The specified timeout is invalid";
+ case SOCKERR_FDSETFULL:
+ return "Unable to create an FDSET";
+ case SOCKERR_TIMEVALFULL:
+ return "Unable to create a TIMEVAL";
+ case SOCKERR_REMSOCKSHUTDOWN:
+ return "The remote socket has shutdown gracefully";
+ case SOCKERR_NOTLISTENING:
+ return "Listen() was not invoked prior to accept()";
+ case SOCKERR_NOTSTREAMSOCK:
+ return "The socket does not support connection-oriented service";
+ case SOCKERR_ALREADYBOUND:
+ return "The socket is already bound to an address";
+ case SOCKERR_NBWITHLINGER:
+ return "The socket is marked non-blocking & SO_LINGER is non-zero";
+ case SOCKERR_ISCONNECTED:
+ return "The socket is already connected";
+ case SOCKERR_NOBUFFERS:
+ return "No buffer space is available";
+ case SOCKERR_HOSTNOTFOUND:
+ return "Authoritative Answer Host not found";
+ case SOCKERR_NODATA:
+ return "Valid name, no data record of requested type";
+ case SOCKERR_BOUNDORCONN:
+ return "The socket has not been bound or is already connected";
+ case SOCKERR_OPNOTSUPP:
+ return "The socket does not support the operation";
+ case SOCKERR_OPTUNSUPP:
+ return "The socket option is not supported";
+ case SOCKERR_OPTARGSINVALID:
+ return "The socket option arguments are invalid";
+ case SOCKERR_SOCKLEVELINVALID:
+ return "The socket level is invalid";
+ case SOCKERR_TIMEOUTFAILURE:
+ return "The timeout operation failed";
+ case SOCKERR_SOCKADDRALLOCFAIL:
+ return "Failed to allocate address structure";
+ case SOCKERR_FDSET_SIZEBAD:
+ return "The calculated maximum size of the file descriptor set is bad";
+ case SOCKERR_UNKNOWNFLAG:
+ return "The flag is unknown";
+ case SOCKERR_MSGSIZE:
+ return "The datagram was too big to fit the specified buffer, so truncated";
+ case SOCKERR_NORECOVERY:
+ return "The operation failed with no recovery possible";
+ case SOCKERR_ARGSINVALID:
+ return "The arguments are invalid";
+ case SOCKERR_BADDESC:
+ return "The socket argument is not a valid file descriptor";
+ case SOCKERR_NOTSOCK:
+ return "The socket argument is not a socket";
+ case SOCKERR_HOSTENTALLOCFAIL:
+ return "Unable to allocate the hostent structure";
+ case SOCKERR_TIMEVALALLOCFAIL:
+ return "Unable to allocate the timeval structure";
+ case SOCKERR_LINGERALLOCFAIL:
+ return "Unable to allocate the linger structure";
+ case SOCKERR_IPMREQALLOCFAIL:
+ return "Unable to allocate the ipmreq structure";
+ case SOCKERR_FDSETALLOCFAIL:
+ return "Unable to allocate the fdset structure";
+ case SOCKERR_OPFAILED:
+ return "Operation failed";
+ case SOCKERR_CONNECTION_REFUSED:
+ return "Connection refused";
+ case SOCKERR_ENETUNREACH:
+ return "Network unreachable";
+ case SOCKERR_EHOSTUNREACH:
+ return "No route to host";
+ case SOCKERR_EPIPE:
+ return "Broken pipe";
+ case SOCKERR_EACCES:
+ return "Permission denied (maybe missing INTERNET permission)";
+
+ default:
+ LOGE("unknown socket error %d", anErrorNum);
+ return "unknown error";
+ }
+}
+
+static int convertError(int errorCode) {
+ switch (errorCode) {
+ case EBADF:
+ return SOCKERR_BADDESC;
+ case ENOBUFS:
+ return SOCKERR_NOBUFFERS;
+ case EOPNOTSUPP:
+ return SOCKERR_OPNOTSUPP;
+ case ENOPROTOOPT:
+ return SOCKERR_OPTUNSUPP;
+ case EINVAL:
+ return SOCKERR_SOCKLEVELINVALID;
+ case ENOTSOCK:
+ return SOCKERR_NOTSOCK;
+ case EINTR:
+ return SOCKERR_INTERRUPTED;
+ case ENOTCONN:
+ return SOCKERR_NOTCONNECTED;
+ case EAFNOSUPPORT:
+ return SOCKERR_BADAF;
+ /* note: CONNRESET not included because it has the same
+ * value as ECONNRESET and they both map to SOCKERR_CONNRESET */
+ case ECONNRESET:
+ return SOCKERR_CONNRESET;
+ case EAGAIN:
+ return SOCKERR_WOULDBLOCK;
+ case EPROTONOSUPPORT:
+ return SOCKERR_BADPROTO;
+ case EFAULT:
+ return SOCKERR_ARGSINVALID;
+ case ETIMEDOUT:
+ return SOCKERR_TIMEOUT;
+ case ECONNREFUSED:
+ return SOCKERR_CONNECTION_REFUSED;
+ case ENETUNREACH:
+ return SOCKERR_ENETUNREACH;
+ case EACCES:
+ return SOCKERR_EACCES;
+ case EPIPE:
+ return SOCKERR_EPIPE;
+ case EHOSTUNREACH:
+ return SOCKERR_EHOSTUNREACH;
+ case EADDRINUSE:
+ return SOCKERR_ADDRINUSE;
+ case EADDRNOTAVAIL:
+ return SOCKERR_ADDRNOTAVAIL;
+ case EMSGSIZE:
+ return SOCKERR_MSGSIZE;
+ default:
+ LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
+ return SOCKERR_OPFAILED;
+ }
+}
+
+static int sockSelect(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout) {
+
+ int result = select(nfds, readfds, writefds, exceptfds, timeout);
+
+ if (result < 0) {
+ if (errno == EINTR) {
+ result = SOCKERR_INTERRUPTED;
+ } else {
+ result = SOCKERR_OPFAILED;
+ }
+ } else if (result == 0) {
+ result = SOCKERR_TIMEOUT;
+ }
+ return result;
+}
+
+#define SELECT_READ_TYPE 0
+#define SELECT_WRITE_TYPE 1
+
+static int selectWait(int handle, int uSecTime, int type) {
+ fd_set fdset;
+ struct timeval time, *timePtr;
+ int result = 0;
+ int size = handle + 1;
+
+ FD_ZERO(&fdset);
+ FD_SET(handle, &fdset);
+
+ if (0 <= uSecTime) {
+ /* Use a timeout if uSecTime >= 0 */
+ memset(&time, 0, sizeof(time));
+ time.tv_usec = uSecTime;
+ timePtr = &time;
+ } else {
+ /* Infinite timeout if uSecTime < 0 */
+ timePtr = NULL;
+ }
+
+ if (type == SELECT_READ_TYPE) {
+ result = sockSelect(size, &fdset, NULL, NULL, timePtr);
+ } else {
+ result = sockSelect(size, NULL, &fdset, NULL, timePtr);
+ }
+ return result;
+}
+
+static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int type) {
+ /* now try reading the socket for the timespan timeout.
+ * if timeout is 0 try forever until the soclets gets ready or until an
+ * exception occurs.
+ */
+ int pollTimeoutUSec = 100000, pollMsec = 100;
+ int finishTime = 0;
+ int timeLeft = timeout;
+ int hasTimeout = timeout > 0 ? 1 : 0;
+ int result = 0;
+ int handle;
+
+ if (hasTimeout) {
+ finishTime = time_msec_clock() + timeout;
+ }
+
+ int poll = 1;
+
+ while (poll) { /* begin polling loop */
+
+ /*
+ * Fetch the handle every time in case the socket is closed.
+ */
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_INTERRUPTED);
+ return -1;
+ }
+
+ if (hasTimeout) {
+
+ if (timeLeft - 10 < pollMsec) {
+ pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
+ }
+
+ result = selectWait(handle, pollTimeoutUSec, type);
+
+ /*
+ * because we are polling at a time smaller than timeout
+ * (presumably) lets treat an interrupt and timeout the same - go
+ * see if we're done timewise, and then just try again if not.
+ */
+ if (SOCKERR_TIMEOUT == result ||
+ SOCKERR_INTERRUPTED == result) {
+
+ timeLeft = finishTime - time_msec_clock();
+
+ if (timeLeft <= 0) {
+ /*
+ * Always throw the "timeout" message because that is
+ * effectively what has happened, even if we happen to
+ * have been interrupted.
+ */
+ jniThrowException(env, "java/net/SocketTimeoutException",
+ netLookupErrorString(SOCKERR_TIMEOUT));
+ } else {
+ continue; // try again
+ }
+
+ } else if (0 > result) {
+ log_socket_close(handle, result);
+ throwSocketException(env, result);
+ }
+ poll = 0;
+
+ } else { /* polling with no timeout (why would you do this?)*/
+
+ result = selectWait(handle, pollTimeoutUSec, type);
+
+ /*
+ * if interrupted (or a timeout) just retry
+ */
+ if (SOCKERR_TIMEOUT == result ||
+ SOCKERR_INTERRUPTED == result) {
+
+ continue; // try again
+ } else if (0 > result) {
+ log_socket_close(handle, result);
+ throwSocketException(env, result);
+ }
+ poll = 0;
+ }
+ } /* end polling loop */
+
+ return result;
+}
+
+/**
+ * A helper method, to set the connect context to a Long object.
+ *
+ * @param env pointer to the JNI library
+ * @param longclass Java Long Object
+ */
+void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
+ jclass descriptorCLS;
+ jfieldID descriptorFID;
+ descriptorCLS = env->FindClass("java/lang/Long");
+ descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+ env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
+};
+
+/**
+ * A helper method, to get the connect context.
+ *
+ * @param env pointer to the JNI library
+ * @param longclass Java Long Object
+ */
+jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
+ jclass descriptorCLS;
+ jfieldID descriptorFID;
+ descriptorCLS = env->FindClass("java/lang/Long");
+ descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+ return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
+};
+
+// typical ip checksum
+unsigned short ip_checksum(unsigned short* buffer, int size) {
+ register unsigned short * buf = buffer;
+ register int bufleft = size;
+ register unsigned long sum = 0;
+
+ while (bufleft > 1) {
+ sum = sum + (*buf++);
+ bufleft = bufleft - sizeof(unsigned short );
+ }
+ if (bufleft) {
+ sum = sum + (*(unsigned char*)buf);
+ }
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ return (unsigned short )(~sum);
+}
+
+/**
+ * Establish a connection to a peer with a timeout. This function is called
+ * repeatedly in order to carry out the connect and to allow other tasks to
+ * proceed on certain platforms. The caller must first call with
+ * step = SOCKET_STEP_START, if the result is SOCKERR_NOTCONNECTED it will then
+ * call it with step = CHECK until either another error or 0 is returned to
+ * indicate the connect is complete. Each time the function should sleep for no
+ * more than timeout milliseconds. If the connect succeeds or an error occurs,
+ * the caller must always end the process by calling the function with
+ * step = SOCKET_STEP_DONE
+ *
+ * @param[in] portLibrary The port library.
+ * @param[in] sock pointer to the unconnected local socket.
+ * @param[in] addr pointer to the sockaddr, specifying remote host/port.
+ * @param[in] timeout the timeout in milliseconds. If timeout is negative,
+ * perform a block operation.
+ * @param[in,out] pointer to context pointer. Filled in on first call and then
+ * to be passed into each subsequent call.
+ *
+ * @return 0, if no errors occurred, otherwise the (negative) error code.
+ */
+static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
+ unsigned int timeout, unsigned int step, jbyte *ctxt) {
+ int rc = 0;
+ struct timeval passedTimeout;
+ int errorVal;
+ socklen_t errorValLen = sizeof(int);
+ struct selectFDSet *context = NULL;
+
+ if (SOCKET_STEP_START == step) {
+
+ context = (struct selectFDSet *) ctxt;
+
+ context->sock = handle;
+ context->nfds = handle + 1;
+
+ if (useAdbNetworking && !isLocalhost(&addr)) {
+
+ // LOGD("+connect to address 0x%08x (via adb)",
+ // addr.sin_addr.s_addr);
+ rc = adb_networking_connect_fd(handle, &addr);
+ // LOGD("-connect ret %d errno %d (via adb)", rc, errno);
+
+ } else {
+ log_socket_connect(handle, ntohl(addr.sin_addr.s_addr),
+ ntohs(addr.sin_port));
+ /* set the socket to non-blocking */
+ int block = JNI_TRUE;
+ rc = ioctl(handle, FIONBIO, &block);
+ if (0 != rc) {
+ return convertError(rc);
+ }
+
+ // LOGD("+connect to address 0x%08x (via normal) on handle %d",
+ // addr.sin_addr.s_addr, handle);
+ do {
+ rc = connect(handle, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr));
+ } while (rc < 0 && errno == EINTR);
+ // LOGD("-connect to address 0x%08x (via normal) returned %d",
+ // addr.sin_addr.s_addr, (int) rc);
+
+ }
+
+ if (rc == -1) {
+ rc = errno;
+ switch (rc) {
+ case EINTR:
+ return SOCKERR_ALREADYBOUND;
+ case EAGAIN:
+ case EINPROGRESS:
+ return SOCKERR_NOTCONNECTED;
+ default:
+ return convertError(rc);
+ }
+ }
+
+ /* we connected right off the bat so just return */
+ return rc;
+
+ } else if (SOCKET_STEP_CHECK == step) {
+ /* now check if we have connected yet */
+
+ context = (struct selectFDSet *) ctxt;
+
+ /*
+ * set the timeout value to be used. Because on some unix platforms we
+ * don't get notified when a socket is closed we only sleep for 100ms
+ * at a time
+ */
+ passedTimeout.tv_sec = 0;
+ if (timeout > 100) {
+ passedTimeout.tv_usec = 100 * 1000;
+ } else if ((int)timeout >= 0) {
+ passedTimeout.tv_usec = timeout * 1000;
+ }
+
+ /* initialize the FD sets for the select */
+ FD_ZERO(&(context->exceptionSet));
+ FD_ZERO(&(context->writeSet));
+ FD_ZERO(&(context->readSet));
+ FD_SET(context->sock, &(context->writeSet));
+ FD_SET(context->sock, &(context->readSet));
+ FD_SET(context->sock, &(context->exceptionSet));
+
+ rc = select(context->nfds,
+ &(context->readSet),
+ &(context->writeSet),
+ &(context->exceptionSet),
+ (int)timeout >= 0 ? &passedTimeout : NULL);
+
+ /* if there is at least one descriptor ready to be checked */
+ if (0 < rc) {
+ /* if the descriptor is in the write set we connected or failed */
+ if (FD_ISSET(context->sock, &(context->writeSet))) {
+
+ if (!FD_ISSET(context->sock, &(context->readSet))) {
+ /* ok we have connected ok */
+ return 0;
+ } else {
+ /* ok we have more work to do to figure it out */
+ if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR,
+ &errorVal, &errorValLen) >= 0) {
+ return errorVal ? convertError(errorVal) : 0;
+ } else {
+ return convertError(errno);
+ }
+ }
+ }
+
+ /* if the descriptor is in the exception set the connect failed */
+ if (FD_ISSET(context->sock, &(context->exceptionSet))) {
+ if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal,
+ &errorValLen) >= 0) {
+ return errorVal ? convertError(errorVal) : 0;
+ }
+ rc = errno;
+ return convertError(rc);
+ }
+
+ } else if (rc < 0) {
+ /* something went wrong with the select call */
+ rc = errno;
+
+ /* if it was EINTR we can just try again. Return not connected */
+ if (EINTR == rc) {
+ return SOCKERR_NOTCONNECTED;
+ }
+
+ /* some other error occured so look it up and return */
+ return convertError(rc);
+ }
+
+ /*
+ * if we get here the timeout expired or the connect had not yet
+ * completed just indicate that the connect is not yet complete
+ */
+ return SOCKERR_NOTCONNECTED;
+ } else if (SOCKET_STEP_DONE == step) {
+ /* we are done the connect or an error occured so clean up */
+ if (handle != -1) {
+ int block = JNI_FALSE;
+ ioctl(handle, FIONBIO, &block);
+ }
+ return 0;
+ }
+ return SOCKERR_ARGSINVALID;
+}
+
+/**
+ * Join/Leave the nominated multicast group on the specified socket.
+ * Implemented by setting the multicast 'add membership'/'drop membership'
+ * option at the HY_IPPROTO_IP level on the socket.
+ *
+ * Implementation note for multicast sockets in general:
+ *
+ * - This code is untested, because at the time of this writing multicast can't
+ * be properly tested on Android due to GSM routing restrictions. So it might
+ * or might not work.
+ *
+ * - The REUSEPORT socket option that Harmony employs is not supported on Linux
+ * and thus also not supported on Android. It's is not needed for multicast
+ * to work anyway (REUSEADDR should suffice).
+ *
+ * @param env pointer to the JNI library.
+ * @param socketP pointer to the hysocket to join/leave on.
+ * @param optVal pointer to the InetAddress, the multicast group to join/drop.
+ *
+ * @exception SocketException if an error occurs during the call
+ */
+static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
+ int ignoreIF, int setSockOptVal) {
+ int result;
+ struct ip_mreq ipmreqP;
+ struct sockaddr_in sockaddrP;
+ int length = sizeof(struct ip_mreq);
+ socklen_t lengthIF = sizeof(struct sockaddr_in);
+
+ /*
+ * JNI objects needed to access the information in the optVal oject
+ * passed in. The object passed in is a GenericIPMreq object
+ */
+ jclass cls;
+ jfieldID multiaddrID;
+ jfieldID interfaceAddrID;
+ jobject multiaddr;
+ jobject interfaceAddr;
+
+ /*
+ * check whether we are getting an InetAddress or an Generic IPMreq, for now
+ * we support both so that we will not break the tests
+ */
+ if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
+
+ ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (!ignoreIF) {
+
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockaddrP,
+ &lengthIF);
+
+ if (0 != result) {
+ throwSocketException (env, convertError(errno));
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
+ }
+
+ result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
+
+ result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ if (0 != result) {
+ throwSocketException (env, convertError(errno));
+ return;
+ }
+
+ } else {
+
+ /* we need the multicast address regardless of the type of address */
+ cls = env->GetObjectClass(optVal);
+ multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
+ multiaddr = env->GetObjectField(optVal, multiaddrID);
+
+ result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
+
+ /* we need to use an IP_MREQ as it is an IPV4 address */
+ interfaceAddrID = env->GetFieldID(cls, "interfaceAddr",
+ "Ljava/net/InetAddress;");
+ interfaceAddr = env->GetObjectField(optVal, interfaceAddrID);
+
+ ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ /*
+ * if an interfaceAddr was passed then use that value, otherwise set the
+ * interface to all 0 to indicate the system should select the interface
+ * used
+ */
+ if (!ignoreIF) {
+ if (NULL != interfaceAddr) {
+
+ result = inetAddressToSocketAddress(env, interfaceAddr, 0,
+ &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
+
+ }
+ }
+
+ /* join/drop the multicast address */
+ result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ if (0 != result) {
+ throwSocketException (env, convertError(errno));
+ return;
+ }
+ }
+}
+
+static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
+ jboolean jcl_supports_ipv6) {
+ // LOGD("ENTER oneTimeInitializationImpl of OSNetworkSystem");
+
+ char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
+ char adbConnectedProperty[PROPERTY_VALUE_MAX];
+
+ property_get("android.net.use-adb-networking", useAdbNetworkingProperty, "");
+ property_get("adb.connected", adbConnectedProperty, "");
+
+ if (strlen((char *)useAdbNetworkingProperty) > 0
+ && strlen((char *)adbConnectedProperty) > 0) {
+ useAdbNetworking = 1;
+ }
+
+ memset(&gCachedFields, 0, sizeof(gCachedFields));
+
+ // initializing InetAddress
+
+ jclass iaddrclass = env->FindClass("java/net/InetAddress");
+
+ if (iaddrclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.net.InetAddress");
+ return;
+ }
+
+ gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
+
+ jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V");
+
+ if (iaddrclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()");
+ return;
+ }
+
+ gCachedFields.iaddr_class_init = iaddrclassinit;
+
+ jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
+ "getByAddress", "([B)Ljava/net/InetAddress;");
+
+ if (iaddrgetbyaddress == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "InetAddress.getByAddress(byte[] val)");
+ return;
+ }
+
+ gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
+
+ jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
+
+ if (iaddripaddress == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "Can't find field InetAddress.ipaddress");
+ return;
+ }
+
+ gCachedFields.iaddr_ipaddress = iaddripaddress;
+
+ // get the GenericIPMreq class
+
+ jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
+
+ if (genericipmreqclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "org.apache.harmony.luni.net.GenericIPMreq");
+ return;
+ }
+
+ gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
+
+ // initializing Integer
+
+ jclass integerclass = env->FindClass("java/lang/Integer");
+
+ if (integerclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.Integer");
+ return;
+ }
+
+ jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
+
+ if (integerclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "Integer.<init>(int val)");
+ return;
+ }
+
+ jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
+
+ if (integerclassvalue == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
+ return;
+ }
+
+ gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
+ gCachedFields.integer_class_init = integerclassinit;
+ gCachedFields.integer_class_value = integerclassvalue;
+
+ // initializing Boolean
+
+ jclass booleanclass = env->FindClass("java/lang/Boolean");
+
+ if (booleanclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.Boolean");
+ return;
+ }
+
+ jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
+
+ if (booleanclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "Boolean.<init>(boolean val)");
+ return;
+ }
+
+ jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
+
+ if (booleanclassvalue == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
+ return;
+ }
+
+ gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
+ gCachedFields.boolean_class_init = booleanclassinit;
+ gCachedFields.boolean_class_value = booleanclassvalue;
+
+ // initializing Byte
+
+ jclass byteclass = env->FindClass("java/lang/Byte");
+
+ if (byteclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.Byte");
+ return;
+ }
+
+ jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
+
+ if (byteclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "Byte.<init>(byte val)");
+ return;
+ }
+
+ jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
+
+ if (byteclassvalue == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
+ return;
+ }
+
+ gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
+ gCachedFields.byte_class_init = byteclassinit;
+ gCachedFields.byte_class_value = byteclassvalue;
+
+ // initializing String
+
+ jclass stringclass = env->FindClass("java/lang/String");
+
+ if (stringclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.lang.String");
+ return;
+ }
+
+ jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
+
+ if (stringclassinit == NULL) {
+ jniThrowException(env, "java/lang/NoSuchMethodError",
+ "String.<init>(byte[] val)");
+ return;
+ }
+
+ gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
+ gCachedFields.string_class_init = stringclassinit;
+
+ // initializing ScoketImpl
+
+ jclass socketimplclass = env->FindClass("java/net/SocketImpl");
+
+ if (socketimplclass == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.net.SocketImpl");
+ return;
+ }
+
+ jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
+
+ if (socketimplport == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
+ return;
+ }
+
+ jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
+ "Ljava/net/InetAddress;");
+
+ if (socketimpladdress == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "SocketImpl.address");
+ return;
+ }
+
+ gCachedFields.socketimpl_address = socketimpladdress;
+ gCachedFields.socketimpl_port = socketimplport;
+
+ gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket");
+ if (gCachedFields.dpack_class == NULL) {
+ jniThrowException(env, "java/lang/ClassNotFoundException",
+ "java.net.DatagramPacket");
+ return;
+ }
+
+ gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class,
+ "address", "Ljava/net/InetAddress;");
+ if (gCachedFields.dpack_address == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "DatagramPacket.address");
+ return;
+ }
+
+ gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
+ "port", "I");
+ if (gCachedFields.dpack_port == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "DatagramPacket.port");
+ return;
+ }
+
+ gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
+ "length", "I");
+ if (gCachedFields.dpack_length == NULL) {
+ jniThrowException(env, "java/lang/NoSuchFieldError",
+ "DatagramPacket.length");
+ return;
+ }
+
+}
+
+static void osNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createSocketImpl");
+
+ int ret = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
+
+ return;
+}
+
+static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createDatagramSocketImpl");
+
+ int ret = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
+
+ return;
+}
+
+static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint address, jint offset, jint count,
+ jint timeout) {
+ // LOGD("ENTER readSocketDirectImpl");
+
+ int handle;
+ jbyte *message = (jbyte *)address;
+ int result, ret, localCount;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ result = selectWait(handle, timeout, SELECT_READ_TYPE);
+
+ if (0 > result) {
+ return 0;
+ }
+
+ localCount = (count < 65536) ? count : 65536;
+
+ do {
+ ret = recv(handle, (jbyte *) message, localCount, SOCKET_NOFLAGS);
+ } while (ret < 0 && errno == EINTR);
+
+ if (0 == ret) {
+ return -1;
+ } else if (ret == -1) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ add_recv_stats(handle, ret);
+ return ret;
+}
+
+static jint osNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count,
+ jint timeout) {
+ // LOGD("ENTER readSocketImpl");
+
+ jbyte *message;
+ int result, localCount;
+
+ jbyte internalBuffer[BUFFERSIZE];
+
+ localCount = (count < 65536) ? count : 65536;
+
+ if (localCount > BUFFERSIZE) {
+ message = (jbyte*)malloc(localCount * sizeof(jbyte));
+ if (message == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for readSocket");
+ return 0;
+ }
+ } else {
+ message = (jbyte *)internalBuffer;
+ }
+
+ result = osNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
+ (jint) message, offset, count, timeout);
+
+ if (result > 0) {
+ env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
+ }
+
+ if (((jbyte *)message) != internalBuffer) {
+ free(( jbyte *)message);
+ }
+
+ return result;
+}
+
+static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint address, jint offset, jint count) {
+ // LOGD("ENTER writeSocketDirectImpl");
+
+ int handle;
+ jbyte *message = (jbyte *)address;
+ int result = 0, sent = 0;
+
+ if (count <= 0) {
+ return 0;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+
+ if (SOCKERR_WOULDBLOCK == err){
+ jclass socketExClass,errorCodeExClass;
+ jmethodID errorCodeExConstructor, socketExConstructor,socketExCauseMethod;
+ jobject errorCodeEx, socketEx;
+ const char* errorMessage = netLookupErrorString(err);
+ jstring errorMessageString = env->NewStringUTF(errorMessage);
+
+ errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
+ if (!errorCodeExClass){
+ return 0;
+ }
+ errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
+ if (!errorCodeExConstructor){
+ return 0;
+ }
+ errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
+
+ socketExClass = env->FindClass("java/net/SocketException");
+ if (!socketExClass) {
+ return 0;
+ }
+ socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
+ if (!socketExConstructor) {
+ return 0;
+ }
+ socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
+ socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+ env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
+ env->Throw((jthrowable)socketEx);
+ return 0;
+ }
+ throwSocketException(env, err);
+ return 0;
+ }
+
+ add_send_stats(handle, result);
+ return result;
+}
+
+static jint osNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
+ // LOGD("ENTER writeSocketImpl");
+
+ jbyte *message;
+ int sent = 0;
+ jint result = 0;
+
+/* TODO: ARRAY PINNING */
+#define INTERNAL_SEND_BUFFER_MAX 512
+ jbyte internalBuffer[INTERNAL_SEND_BUFFER_MAX];
+
+ if (count > INTERNAL_SEND_BUFFER_MAX) {
+ message = (jbyte*)malloc(count * sizeof( jbyte));
+ if (message == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for writeSocket");
+ return 0;
+ }
+ } else {
+ message = (jbyte *)internalBuffer;
+ }
+
+ env->GetByteArrayRegion(data, offset, count, message);
+
+ result = osNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
+ (jint) message, offset, count);
+
+ if (( jbyte *)message != internalBuffer) {
+ free(( jbyte *)message);
+ }
+#undef INTERNAL_SEND_BUFFER_MAX
+ return result;
+}
+
+static void osNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean nonblocking) {
+ // LOGD("ENTER setNonBlockingImpl");
+
+ int handle;
+ int result;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ int block = nonblocking;
+
+ result = ioctl(handle, FIONBIO, &block);
+
+ if (result == -1) {
+ throwSocketException(env, convertError(errno));
+ }
+}
+
+static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port);
+
+static jint osNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jint timeout, jint trafficClass,
+ jobject inetAddr, jint port, jint step, jbyteArray passContext) {
+ // LOGD("ENTER connectWithTimeoutSocketImpl");
+
+ int handle;
+ int result = 0;
+ struct sockaddr_in address;
+ jbyte *context = NULL;
+
+ memset(&address, 0, sizeof(address));
+
+ address.sin_family = AF_INET;
+
+ result = inetAddressToSocketAddress(env, inetAddr, port,
+ (struct sockaddr_in *) &address);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return result;
+ }
+
+ // Check if we're using adb networking and redirect in case it is used.
+ if (useAdbNetworking && !isLocalhost(&address)) {
+ return osNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
+ trafficClass, inetAddr, port);
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return -1;
+ }
+
+ address.sin_port = htons(port);
+
+ context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
+
+ switch (step) {
+ case SOCKET_CONNECT_STEP_START:
+ result = sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_START, context);
+ break;
+ case SOCKET_CONNECT_STEP_CHECK:
+ result = sockConnectWithTimeout(handle, address, timeout,
+ SOCKET_STEP_CHECK, context);
+ break;
+ }
+
+ env->ReleasePrimitiveArrayCritical(passContext, context, JNI_ABORT);
+
+ if (0 == result) {
+ /* connected , so stop here */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
+ } else if (result != SOCKERR_NOTCONNECTED) {
+ /* can not connect... */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
+ if (result == SOCKERR_EACCES) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(result));
+ }
+ }
+
+ return result;
+}
+
+static void osNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jint remotePort, jint timeout,
+ jint trafficClass, jobject inetAddr) {
+ // LOGD("ENTER connectStreamWithTimeoutSocketImpl");
+
+ int result = 0;
+ int handle;
+ struct sockaddr_in address;
+ jbyte *context = NULL;
+ int remainingTimeout = timeout;
+ int passedTimeout = 0;
+ int finishTime = 0;
+ int blocking = 0;
+ char hasTimeout = timeout > 0;
+
+ /* if a timeout was specified calculate the finish time value */
+ if (hasTimeout) {
+ finishTime = time_msec_clock() + (int) timeout;
+ }
+
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ } else {
+ result = inetAddressToSocketAddress(env, inetAddr, remotePort,
+ (struct sockaddr_in *) &address);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ // Check if we're using adb networking and redirect in case it is used.
+ if (useAdbNetworking && !isLocalhost(&address)) {
+ int retVal = osNetworkSystem_connectSocketImpl(env, clazz,
+ fileDescriptor, trafficClass, inetAddr, remotePort);
+ if (retVal != 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ }
+ return;
+ }
+
+ /*
+ * we will be looping checking for when we are connected so allocate
+ * the descriptor sets that we will use
+ */
+ context =(jbyte *) malloc(sizeof(struct selectFDSet));
+
+ if (NULL == context) {
+ throwSocketException(env, SOCKERR_NOBUFFERS);
+ return;
+ }
+
+ result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
+ if (0 == result) {
+ /* ok we connected right away so we are done */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
+ goto bail;
+ } else if (result != SOCKERR_NOTCONNECTED) {
+ log_socket_close(handle, result);
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
+ context);
+ /* we got an error other than NOTCONNECTED so we cannot continue */
+ if (SOCKERR_EACCES == result) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ throwSocketException(env, result);
+ }
+ goto bail;
+ }
+
+ while (SOCKERR_NOTCONNECTED == result) {
+ passedTimeout = remainingTimeout;
+
+ /*
+ * ok now try and connect. Depending on the platform this may sleep
+ * for up to passedTimeout milliseconds
+ */
+ result = sockConnectWithTimeout(handle, address, passedTimeout,
+ SOCKET_STEP_CHECK, context);
+
+ /*
+ * now check if the socket is still connected.
+ * Do it here as some platforms seem to think they
+ * are connected if the socket is closed on them.
+ */
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ goto bail;
+ }
+
+ /*
+ * check if we are now connected,
+ * if so we can finish the process and return
+ */
+ if (0 == result) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ goto bail;
+ }
+
+ /*
+ * if the error is SOCKERR_NOTCONNECTED then we have not yet
+ * connected and we may not be done yet
+ */
+ if (SOCKERR_NOTCONNECTED == result) {
+ /* check if the timeout has expired */
+ if (hasTimeout) {
+ remainingTimeout = finishTime - time_msec_clock();
+ if (remainingTimeout <= 0) {
+ log_socket_close(handle, result);
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ jniThrowException(env,
+ "java/net/SocketTimeoutException",
+ netLookupErrorString(result));
+ goto bail;
+ }
+ } else {
+ remainingTimeout = 100;
+ }
+ } else {
+ log_socket_close(handle, result);
+ sockConnectWithTimeout(handle, address, remainingTimeout,
+ SOCKET_STEP_DONE, context);
+ if ((SOCKERR_CONNRESET == result) ||
+ (SOCKERR_CONNECTION_REFUSED == result) ||
+ (SOCKERR_ADDRNOTAVAIL == result) ||
+ (SOCKERR_ADDRINUSE == result) ||
+ (SOCKERR_ENETUNREACH == result)) {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(result));
+ } else if (SOCKERR_EACCES == result) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ throwSocketException(env, result);
+ }
+ goto bail;
+ }
+ }
+ }
+
+bail:
+
+ /* free the memory for the FD set */
+ if (context != NULL) {
+ free(context);
+ }
+}
+
+static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
+ //LOGD("ENTER direct-call connectSocketImpl\n");
+
+ struct sockaddr_in address;
+ int ret;
+ int handle;
+ jbyteArray java_in_addr;
+
+ memset(&address, 0, sizeof(address));
+
+ address.sin_family = AF_INET;
+
+ ret = inetAddressToSocketAddress(env, inetAddr, port,
+ (struct sockaddr_in *) &address);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return ret;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return -1;
+ }
+
+ address.sin_port = htons(port);
+
+ if (useAdbNetworking && !isLocalhost(&address)) {
+
+ // LOGD("+connect to address 0x%08x port %d (via adb)",
+ // address.sin_addr.s_addr, (int) port);
+ ret = adb_networking_connect_fd(handle, &address);
+ // LOGD("-connect ret %d errno %d (via adb)", ret, errno);
+
+ } else {
+
+ // call this method with a timeout of zero
+ osNetworkSystem_connectStreamWithTimeoutSocketImpl(env, clazz,
+ fileDescriptor, port, 0, trafficClass, inetAddr);
+ if (env->ExceptionOccurred() != 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+
+ }
+
+ if (ret < 0) {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(convertError(errno)));
+ return ret;
+ }
+
+ return ret;
+}
+
+static void osNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint port, jobject inetAddress) {
+ // LOGD("ENTER socketBindImpl");
+
+ struct sockaddr_in sockaddress;
+ int ret;
+ int handle;
+
+ ret = inetAddressToSocketAddress(env, inetAddress, port,
+ (struct sockaddr_in *) &sockaddress);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
+
+ if (ret < 0) {
+ jniThrowException(env, "java/net/BindException",
+ netLookupErrorString(convertError(errno)));
+ return;
+ }
+}
+
+static void osNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint backlog) {
+ // LOGD("ENTER listenStreamSocketImpl");
+
+ int ret;
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ ret = listen(handle, backlog);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+}
+
+static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor) {
+ // LOGD("ENTER availableStreamImpl");
+
+ int handle;
+ char message[BUFFERSIZE];
+
+ int result;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ do {
+ result = selectWait(handle, 1, SELECT_READ_TYPE);
+
+ if (SOCKERR_TIMEOUT == result) {
+ // The read operation timed out, so answer 0 bytes available
+ return 0;
+ } else if (SOCKERR_INTERRUPTED == result) {
+ continue;
+ } else if (0 > result) {
+ log_socket_close(handle, result);
+ throwSocketException(env, result);
+ return 0;
+ }
+ } while (SOCKERR_INTERRUPTED == result);
+
+ result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
+
+ if (0 > result) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ add_recv_stats(handle, result);
+ return result;
+}
+
+static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
+ // LOGD("ENTER acceptSocketImpl");
+
+ union {
+ struct sockaddr address;
+ struct sockaddr_in in_address;
+ } sa;
+
+ int ret;
+ int retFD;
+ int result;
+ int handle;
+ socklen_t addrlen;
+
+ if (newSocket == NULL) {
+ throwNullPointerException(env);
+ return;
+ }
+
+ result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
+
+ if (0 > result) {
+ return;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fdServer);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ do {
+ addrlen = sizeof(sa);
+ ret = accept(handle, &(sa.address), &addrlen);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+
+ retFD = ret;
+
+ /* For AF_INET / inetOrLocal == true only: put
+ * peer address and port in instance variables
+ * We don't bother for UNIX domain sockets, since most peers are
+ * anonymous anyway
+ */
+ if (sa.address.sa_family == AF_INET) {
+ // inetOrLocal should also be true
+
+ jobject inetAddress;
+
+ inetAddress = structInToInetAddress(env, &(sa.in_address.sin_addr));
+
+ if (inetAddress == NULL) {
+ close(retFD);
+ newSocket = NULL;
+ return;
+ }
+
+ env->SetObjectField(newSocket,
+ gCachedFields.socketimpl_address, inetAddress);
+
+ env->SetIntField(newSocket, gCachedFields.socketimpl_port,
+ ntohs(sa.in_address.sin_port));
+ }
+
+ jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
+}
+
+static jboolean osNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor) {
+ // LOGD("ENTER supportsUrgentDataImpl");
+
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+static void osNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyte value) {
+ // LOGD("ENTER sendUrgentDataImpl");
+
+ int handle;
+ int result;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ result = send(handle, (jbyte *) &value, 1, MSG_OOB);
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+}
+
+static void osNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
+ jobject fd, jint port, jint trafficClass, jobject inetAddress) {
+ // LOGD("ENTER connectDatagramImpl2");
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ struct sockaddr_in sockAddr;
+ int ret;
+
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+ log_socket_connect(handle, ntohl(sockAddr.sin_addr.s_addr), port);
+ int result = connect(handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+}
+
+static void osNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd) {
+ // LOGD("ENTER disconnectDatagramImpl");
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ struct sockaddr_in *sockAddr;
+ socklen_t sockAddrLen = sizeof(struct sockaddr_in);
+ sockAddr = (struct sockaddr_in *) malloc(sockAddrLen);
+ memset(sockAddr, 0, sockAddrLen);
+
+ sockAddr->sin_family = AF_UNSPEC;
+ int result = connect(handle, (struct sockaddr *)sockAddr, sockAddrLen);
+ free(sockAddr);
+
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+}
+
+static jboolean osNetworkSystem_socketBindImpl2(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint port, jboolean bindToDevice,
+ jobject inetAddress) {
+ // LOGD("ENTER socketBindImpl2");
+
+ struct sockaddr_in sockaddress;
+ int ret;
+ int handle;
+
+ ret = inetAddressToSocketAddress(env, inetAddress, port,
+ (struct sockaddr_in *) &sockaddress);
+
+ if (ret < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
+ return 0;
+ }
+
+ return 0;
+}
+
+static jint osNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject sender, jint receiveTimeout) {
+ // LOGD("ENTER peekDatagramImpl");
+
+ int port = -1;
+
+ int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+ if (0> result) {
+ return (jint) 0;
+ }
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ struct sockaddr_in sockAddr;
+ socklen_t sockAddrLen = sizeof(sockAddr);
+
+ int length = recvfrom(handle, NULL, 0, MSG_PEEK,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+
+ if (length < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+
+ if (socketAddressToInetAddress(env, &sockAddr, sender, &port) < 0) {
+ throwIOExceptionStr(env, "Address conversion failed");
+ return -1;
+ }
+ add_recv_stats(handle, length);
+ return port;
+}
+
+static jint osNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject packet, jint address, jint offset, jint length,
+ jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveDatagramDirectImpl");
+
+ int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+ if (0 > result) {
+ return (jint) 0;
+ }
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ struct sockaddr_in sockAddr;
+ socklen_t sockAddrLen = sizeof(sockAddr);
+
+ int mode = peek ? MSG_PEEK : 0;
+
+ int actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+
+ if (actualLength < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+
+ if (packet != NULL) {
+ int port = ntohs(sockAddr.sin_port);
+ jbyteArray addr = env->NewByteArray(sizeof(struct in_addr));
+ if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
+ jniThrowException(env, "java/net/SocketException",
+ "Could not set address of packet.");
+ return 0;
+ }
+ jobject sender = env->CallStaticObjectMethod(
+ gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
+ addr);
+ env->SetObjectField(packet, gCachedFields.dpack_address, sender);
+ env->SetIntField(packet, gCachedFields.dpack_port, port);
+ env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+ }
+ add_recv_stats(handle, actualLength);
+ return actualLength;
+}
+
+static jint osNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
+ jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveDatagramImpl");
+
+ int localLength = (length < 65536) ? length : 65536;
+ jbyte *bytes = (jbyte*) malloc(localLength);
+ if (bytes == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for receiveDatagram");
+ return 0;
+ }
+
+ int actualLength = osNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
+ packet, (jint)bytes, offset, localLength, receiveTimeout, peek);
+
+ if (actualLength > 0) {
+ env->SetByteArrayRegion(data, offset, actualLength, bytes);
+ }
+ free(bytes);
+
+ return actualLength;
+}
+
+static jint osNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
+ jclass clazz, jobject fd, jobject packet, jint address, jint offset,
+ jint length, jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveConnectedDatagramDirectImpl");
+
+ int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+
+ if (0 > result) {
+ return 0;
+ }
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ int mode = peek ? MSG_PEEK : 0;
+
+ int actualLength = recvfrom(handle,
+ (char*)(address + offset), length, mode, NULL, NULL);
+
+ if (actualLength < 0) {
+ jniThrowException(env, "java/net/PortUnreachableException", "");
+ return 0;
+ }
+
+ if ( packet != NULL) {
+ env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+ }
+ add_recv_stats(handle, actualLength);
+ return actualLength;
+}
+
+static jint osNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
+ jint receiveTimeout, jboolean peek) {
+ // LOGD("ENTER receiveConnectedDatagramImpl");
+
+ int localLength = (length < 65536) ? length : 65536;
+ jbyte *bytes = (jbyte*) malloc(localLength);
+ if (bytes == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for recvConnectedDatagram");
+ return 0;
+ }
+
+ int actualLength = osNetworkSystem_recvConnectedDatagramDirectImpl(env,
+ clazz, fd, packet, (jint)bytes, offset, localLength,
+ receiveTimeout, peek);
+
+ if (actualLength > 0) {
+ env->SetByteArrayRegion(data, offset, actualLength, bytes);
+ }
+ free(bytes);
+
+ return actualLength;
+}
+
+static jint osNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jint address, jint offset, jint length, jint port,
+ jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
+ // LOGD("ENTER sendDatagramDirectImpl");
+
+ int result = 0;
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ struct sockaddr_in receiver;
+
+ if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ result = sendto(handle, (char*)(address + offset), length, SOCKET_NOFLAGS,
+ (struct sockaddr*)&receiver, sizeof(receiver));
+
+ if (result < 0) {
+ int err = convertError(errno);
+ if ((SOCKERR_CONNRESET == err)
+ || (SOCKERR_CONNECTION_REFUSED == err)) {
+ return 0;
+ } else {
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ }
+ add_send_stats(handle, result);
+ return result;
+}
+
+static jint osNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jbyteArray data, jint offset, jint length, jint port,
+ jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
+ // LOGD("ENTER sendDatagramImpl");
+
+ jbyte *bytes = env->GetByteArrayElements(data, NULL);
+ int actualLength = osNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
+ (jint)bytes, offset, length, port, bindToDevice, trafficClass,
+ inetAddress);
+ env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
+
+ return actualLength;
+}
+
+static jint osNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
+ jclass clazz, jobject fd, jint address, jint offset, jint length,
+ jboolean bindToDevice) {
+ // LOGD("ENTER sendConnectedDatagramDirectImpl");
+
+ int handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ int result = send(handle, (char*)(address + offset), length, 0);
+
+ if (result < 0) {
+ int err = convertError(errno);
+ if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
+ return 0;
+ } else {
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ }
+ add_send_stats(handle, length);
+ return result;
+}
+
+static jint osNetworkSystem_sendConnectedDatagramImpl(JNIEnv* env, jclass clazz,
+ jobject fd, jbyteArray data, jint offset, jint length,
+ jboolean bindToDevice) {
+ // LOGD("ENTER sendConnectedDatagramImpl");
+
+ jbyte *bytes = env->GetByteArrayElements(data, NULL);
+ int actualLength = osNetworkSystem_sendConnectedDatagramDirectImpl(env,
+ clazz, fd, (jint)bytes, offset, length, bindToDevice);
+ env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
+
+ return actualLength;
+}
+
+static void osNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createServerStreamSocketImpl");
+
+ if (fileDescriptor == NULL) {
+ throwNullPointerException(env);
+ return;
+ }
+
+ int handle = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (handle < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
+
+ int value = 1;
+
+ setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
+}
+
+static void osNetworkSystem_createMulticastSocketImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createMulticastSocketImpl");
+
+ int handle = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (handle < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ return;
+ }
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
+
+ int value = 1;
+
+ // setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
+ setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
+}
+
+/*
+ * @param timeout in milliseconds. If zero, block until data received
+ */
+static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count,
+ jint timeout) {
+ // LOGD("ENTER receiveStreamImpl");
+
+ int result;
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ // Cap read length to available buf size
+ int spaceAvailable = env->GetArrayLength(data) - offset;
+ int localCount = count < spaceAvailable? count : spaceAvailable;
+
+ jboolean isCopy;
+ jbyte *body = env->GetByteArrayElements(data, &isCopy);
+
+ // set timeout
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
+ sizeof(struct timeval));
+
+ do {
+ result = recv(handle, body + offset, localCount, SOCKET_NOFLAGS);
+ } while (result < 0 && errno == EINTR);
+
+ env->ReleaseByteArrayElements(data, body, 0);
+
+ /*
+ * If no bytes are read, return -1 to signal 'endOfFile'
+ * to the Java input stream
+ */
+ if (0 < result) {
+ add_recv_stats(handle, result);
+ return result;
+ } else if (0 == result) {
+ return -1;
+ } else {
+ // If EAGAIN or EWOULDBLOCK, read timed out
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ jniThrowException(env, "java/net/SocketTimeoutException",
+ netLookupErrorString(SOCKERR_TIMEOUT));
+ } else {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ }
+ return 0;
+ }
+}
+
+static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
+ // LOGD("ENTER sendStreamImpl");
+
+ int handle = 0;
+ int result = 0, sent = 0;
+
+ jboolean isCopy;
+ jbyte *message = env->GetByteArrayElements(data, &isCopy);
+
+ // Cap write length to available buf size
+ int spaceAvailable = env->GetArrayLength(data) - offset;
+ if (count > spaceAvailable) count = spaceAvailable;
+
+ while (sent < count) {
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env,
+ sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+ env->ReleaseByteArrayElements(data, message, 0);
+ return 0;
+ }
+
+ // LOGD("before select %d", count);
+ selectWait(handle, SEND_RETRY_TIME, SELECT_WRITE_TYPE);
+ result = send(handle, (jbyte *)message + offset + sent,
+ (int) count - sent, SOCKET_NOFLAGS);
+
+ if (result < 0) {
+ result = errno;
+ if (result == EAGAIN ||result == EWOULDBLOCK) {
+ // LOGD("write blocked %d", sent);
+ continue;
+ }
+ env->ReleaseByteArrayElements(data, message, 0);
+ int err = convertError(result);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return 0;
+ }
+ sent += result;
+ }
+
+ env->ReleaseByteArrayElements(data, message, 0);
+ add_send_stats(handle, sent);
+ return sent;
+}
+
+static void osNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
+ jobject fileDescriptor) {
+ // LOGD("ENTER shutdownInputImpl");
+
+ int ret;
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ ret = shutdown(handle, SHUT_RD);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+}
+
+static void osNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
+ jobject fileDescriptor) {
+ // LOGD("ENTER shutdownOutputImpl");
+
+ int ret;
+ int handle;
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ return;
+ }
+
+ ret = shutdown(handle, SHUT_WR);
+
+ if (ret < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ return;
+ }
+}
+
+static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
+ jobject fd, jbyteArray data, jint offset, jint length, jint port,
+ jobject inetAddress) {
+ // LOGD("ENTER sendDatagramImpl2");
+
+ jbyte *message;
+ jbyte nhostAddrBytes[4];
+ unsigned short nPort;
+ int result = 0, sent = 0;
+ int handle = 0;
+ struct sockaddr_in sockaddrP;
+
+ if (inetAddress != NULL) {
+
+ result = inetAddressToSocketAddress(env, inetAddress, port,
+ (struct sockaddr_in *) &sockaddrP);
+
+ if (result < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return 0;
+ }
+ }
+
+ message = (jbyte*) malloc(length * sizeof(jbyte));
+ if (message == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError",
+ "couldn't allocate enough memory for readSocket");
+ return 0;
+ }
+
+ env->GetByteArrayRegion(data, offset, length, message);
+
+ while (sent < length) {
+ handle = jniGetFDFromFileDescriptor(env, fd);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env,
+ sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+ free(message);
+ return 0;
+ }
+
+ result = sendto(handle, (char *) (message + sent),
+ (int) (length - sent), SOCKET_NOFLAGS,
+ (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
+
+ if (result < 0) {
+ int err = convertError(errno);
+ log_socket_close(handle, err);
+ throwSocketException(env, err);
+ free(message);
+ return 0;
+ }
+
+ sent += result;
+ }
+
+ free(message);
+ add_send_stats(handle, sent);
+ return sent;
+}
+
+static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
+ jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
+ jint countWriteC, jintArray outFlags, jlong timeout) {
+ // LOGD("ENTER selectImpl");
+
+ struct timeval timeP;
+ int result = 0;
+ int size = 0;
+ jobject gotFD;
+ fd_set *fdset_read,*fdset_write;
+ int handle;
+ jboolean isCopy ;
+ jint *flagArray;
+ int val;
+ unsigned int time_sec = (unsigned int)timeout/1000;
+ unsigned int time_msec = (unsigned int)(timeout%1000);
+
+ fdset_read = (fd_set *)malloc(sizeof(fd_set));
+ fdset_write = (fd_set *)malloc(sizeof(fd_set));
+
+ FD_ZERO(fdset_read);
+ FD_ZERO(fdset_write);
+
+ for (val = 0; val<countReadC; val++) {
+
+ gotFD = env->GetObjectArrayElement(readFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ FD_SET(handle, fdset_read);
+
+ if (0 > (size - handle)) {
+ size = handle;
+ }
+ }
+
+ for (val = 0; val<countWriteC; val++) {
+
+ gotFD = env->GetObjectArrayElement(writeFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ FD_SET(handle, fdset_write);
+
+ if (0 > (size - handle)) {
+ size = handle;
+ }
+ }
+
+ /* the size is the max_fd + 1 */
+ size =size + 1;
+
+ if (0 > size) {
+ result = SOCKERR_FDSET_SIZEBAD;
+ } else {
+ /* only set when timeout >= 0 (non-block)*/
+ if (0 <= timeout) {
+
+ timeP.tv_sec = time_sec;
+ timeP.tv_usec = time_msec*1000;
+
+ result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
+
+ } else {
+ result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
+ }
+ }
+
+ if (0 < result) {
+ /*output the result to a int array*/
+ flagArray = env->GetIntArrayElements(outFlags, &isCopy);
+
+ for (val=0; val<countReadC; val++) {
+ gotFD = env->GetObjectArrayElement(readFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ if (FD_ISSET(handle,fdset_read)) {
+ flagArray[val] = SOCKET_OP_READ;
+ } else {
+ flagArray[val] = SOCKET_OP_NONE;
+ }
+ }
+
+ for (val=0; val<countWriteC; val++) {
+
+ gotFD = env->GetObjectArrayElement(writeFDArray,val);
+
+ handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+ if (FD_ISSET(handle,fdset_write)) {
+ flagArray[val+countReadC] = SOCKET_OP_WRITE;
+ } else {
+ flagArray[val+countReadC] = SOCKET_OP_NONE;
+ }
+ }
+
+ env->ReleaseIntArrayElements(outFlags, flagArray, 0);
+ }
+
+ free(fdset_write);
+ free(fdset_read);
+
+ /* return both correct and error result, let java handle the exception*/
+ return result;
+}
+
+static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
+ jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
+ // LOGD("ENTER getSocketLocalAddressImpl");
+
+ struct sockaddr_in addr;
+ socklen_t addrLen = sizeof(addr);
+
+ memset(&addr, 0, addrLen);
+
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ int result;
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
+ return NULL;
+ }
+
+ result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
+
+ // Spec says ignore all errors
+
+ return structInToInetAddress(env, &(addr.sin_addr));
+
+}
+
+static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean preferIPv6Addresses) {
+ // LOGD("ENTER getSocketLocalPortImpl");
+
+ struct sockaddr_in addr;
+ socklen_t addrLen = sizeof(addr);
+
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ int result;
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
+ return 0;
+ }
+
+ result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
+
+ if (0 != result) {
+ // The java spec does not indicate any exceptions on this call
+ return 0;
+ } else {
+ return ntohs(addr.sin_port);
+ }
+}
+
+static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint anOption) {
+ // LOGD("ENTER getSocketOptionImpl");
+
+ int handle;
+ int intValue = 0;
+ socklen_t intSize = sizeof(int);
+ unsigned char byteValue = 0;
+ socklen_t byteSize = sizeof(unsigned char);
+ int result;
+ struct sockaddr_in sockVal;
+ socklen_t sockSize = sizeof(sockVal);
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return NULL;
+ }
+
+ switch ((int) anOption & 0xffff) {
+ case JAVASOCKOPT_SO_LINGER: {
+ struct linger lingr;
+ socklen_t size = sizeof(struct linger);
+ result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ if (!lingr.l_onoff) {
+ intValue = -1;
+ } else {
+ intValue = lingr.l_linger;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_TCP_NODELAY: {
+ if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
+ return NULL;
+ }
+ result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_MCAST_TTL: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
+ return newJavaLangByte(env, 0);
+ }
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteValue, &byteSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
+ }
+ case JAVASOCKOPT_MCAST_INTERFACE: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return NULL;
+ }
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return structInToInetAddress(env, &(sockVal.sin_addr));
+ }
+ case JAVASOCKOPT_SO_SNDBUF: {
+ result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_SO_RCVBUF: {
+ result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_SO_BROADCAST: {
+ result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_SO_REUSEADDR: {
+ result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_SO_KEEPALIVE: {
+ result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_SO_OOBINLINE: {
+ result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_IP_MULTICAST_LOOP: {
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangBoolean(env, intValue);
+ }
+ case JAVASOCKOPT_IP_TOS: {
+ result = getsockopt(handle, IPPROTO_IP, IP_TOS, &intValue, &intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, intValue);
+ }
+ case JAVASOCKOPT_SO_RCVTIMEOUT: {
+ struct timeval timeout;
+ socklen_t size = sizeof(timeout);
+ result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+ return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
+ }
+ default: {
+ throwSocketException(env, SOCKERR_OPTUNSUPP);
+ return NULL;
+ }
+ }
+
+}
+
+static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jint anOption, jobject optVal) {
+ // LOGD("ENTER setSocketOptionImpl");
+
+ int handle, result;
+ int intVal, intSize = sizeof(int);
+ unsigned char byteVal, byteSize = sizeof(unsigned char);
+ struct sockaddr_in sockVal;
+ int sockSize = sizeof(sockVal);
+
+ if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
+ intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
+ } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
+ intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
+ } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
+ byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
+ } else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
+ if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+ } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
+ // we'll use optVal directly
+ } else {
+ throwSocketException(env, SOCKERR_OPTUNSUPP);
+ return;
+ }
+
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ switch ((int) anOption & 0xffff) {
+ case JAVASOCKOPT_SO_LINGER: {
+ struct linger lingr;
+ lingr.l_onoff = intVal > 0 ? 1 : 0;
+ lingr.l_linger = intVal;
+ result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
+ sizeof(struct linger));
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_TCP_NODELAY: {
+ if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
+ return;
+ }
+ result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_MCAST_TTL: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
+ return;
+ }
+ result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteVal, byteSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
+ mcastAddDropMembership(env, handle, optVal,
+ (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
+ return;
+ }
+
+ case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
+ mcastAddDropMembership(env, handle, optVal,
+ (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
+ return;
+ }
+
+ case JAVASOCKOPT_MCAST_INTERFACE: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return;
+ }
+ result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, sockSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_SNDBUF: {
+ result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_RCVBUF: {
+ result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_BROADCAST: {
+ result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_REUSEADDR: {
+ result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+ case JAVASOCKOPT_SO_KEEPALIVE: {
+ result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_OOBINLINE: {
+ result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_IP_MULTICAST_LOOP: {
+ result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_IP_TOS: {
+ result = setsockopt(handle, IPPROTO_IP, IP_TOS, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT: {
+ // SO_REUSEPORT doesn't need to get set on this System
+ result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ case JAVASOCKOPT_SO_RCVTIMEOUT: {
+ struct timeval timeout;
+ timeout.tv_sec = intVal / 1000;
+ timeout.tv_usec = (intVal % 1000) * 1000;
+ result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
+ sizeof(struct timeval));
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
+ default: {
+ throwSocketException(env, SOCKERR_OPTUNSUPP);
+ }
+ }
+}
+
+static jint osNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
+ // LOGD("ENTER getSocketFlagsImpl");
+
+ // Not implemented by harmony
+ return 0;
+}
+
+static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor) {
+ // LOGD("ENTER socketCloseImpl");
+
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (handle == 0 || handle == -1) {
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ return;
+ }
+
+ log_socket_close(handle, SOCKET_CLOSE_LOCAL);
+
+ jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
+
+ close(handle);
+}
+
+static jobject osNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
+ jbyteArray addrStr) {
+ // LOGD("ENTER getHostByAddrImpl");
+
+ if (addrStr == NULL) {
+ throwNullPointerException(env);
+ return JNI_FALSE;
+ }
+
+ jstring address = (jstring)newJavaLangString(env, addrStr);
+ jstring result;
+ const char* addr = env->GetStringUTFChars(address, NULL);
+
+ struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
+
+ if (ent != NULL && ent->h_name != NULL) {
+ result = env->NewStringUTF(ent->h_name);
+ } else {
+ result = NULL;
+ }
+
+ env->ReleaseStringUTFChars(address, addr);
+
+ return result;
+}
+
+static jobject osNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
+ jstring nameStr, jboolean preferIPv6Addresses) {
+ // LOGD("ENTER getHostByNameImpl");
+
+ if (nameStr == NULL) {
+ throwNullPointerException(env);
+ return NULL;
+ }
+
+ const char* name = env->GetStringUTFChars(nameStr, NULL);
+
+ if (useAdbNetworking) {
+
+ union {
+ struct in_addr a;
+ jbyte j[4];
+ } outaddr;
+
+ // LOGD("ADB networking: +gethostbyname '%s'", name);
+ int err;
+ err = adb_networking_gethostbyname(name, &(outaddr.a));
+
+ env->ReleaseStringUTFChars(nameStr, name);
+#if 0
+ LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
+ err, (unsigned int)outaddr.a.s_addr,
+ outaddr.j[0],outaddr.j[1],
+ outaddr.j[2],outaddr.j[3]);
+#endif
+
+ if (err < 0) {
+ return NULL;
+ } else {
+ jbyteArray addr = env->NewByteArray(4);
+ env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
+ return addr;
+ }
+ } else {
+
+ // normal case...no adb networking
+ struct hostent* ent = gethostbyname(name);
+
+ env->ReleaseStringUTFChars(nameStr, name);
+
+ if (ent != NULL && ent->h_length > 0) {
+ jbyteArray addr = env->NewByteArray(4);
+ jbyte v[4];
+ memcpy(v, ent->h_addr, 4);
+ env->SetByteArrayRegion(addr, 0, 4, v);
+ return addr;
+ } else {
+ return NULL;
+ }
+ }
+}
+
+static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
+ jobject sender, jbyteArray address) {
+ // LOGD("ENTER setInetAddressImpl");
+
+ env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
+}
+
+static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
+ // LOGD("ENTER inheritedChannelImpl");
+
+ int socket = 0;
+ int opt;
+ socklen_t length = sizeof(opt);
+ int socket_type;
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ jclass channel_class, socketaddr_class, serverSocket_class, socketImpl_class;
+ jobject channel_object = NULL, socketaddr_object, serverSocket_object;
+ jobject fd_object, addr_object, localAddr_object, socketImpl_object;
+ jfieldID port_field, socketaddr_field, bound_field, fd_field;
+ jfieldID serverSocket_field, socketImpl_field, addr_field, localAddr_field;
+ jmethodID channel_new;
+ jbyteArray addr_array;
+ struct sockaddr_in *sock;
+ jbyte * address;
+ jbyte * localAddr;
+ jboolean jtrue = JNI_TRUE;
+
+ if (0 != getsockopt(socket, SOL_SOCKET, SO_TYPE, &opt, &length)) {
+ return NULL;
+ }
+ if (SOCK_STREAM !=opt && SOCK_DGRAM !=opt) {
+ return NULL;
+ }
+ socket_type = opt;
+
+ length = sizeof(struct sockaddr);
+ if (0 != getsockname(socket, (struct sockaddr *)&local_addr, &length)) {
+ return NULL;
+ } else {
+ if (AF_INET != local_addr.sin_family || length != sizeof(struct sockaddr)) {
+ return NULL;
+ }
+ localAddr = (jbyte*) malloc(sizeof(jbyte)*4);
+ if (NULL == localAddr) {
+ return NULL;
+ }
+ memcpy (localAddr, &(local_addr.sin_addr.s_addr), 4);
+ }
+ if (0 != getpeername(socket, (struct sockaddr *)&remote_addr, &length)) {
+ remote_addr.sin_port = 0;
+ remote_addr.sin_addr.s_addr = 0;
+ address = (jbyte*) malloc(sizeof(jbyte)*4);
+ bzero(address, sizeof(jbyte)*4);
+ } else {
+ if (AF_INET != remote_addr.sin_family
+ || length != sizeof(struct sockaddr)) {
+ return NULL;
+ }
+ address = (jbyte*) malloc(sizeof(jbyte)*4);
+ memcpy (address, &(remote_addr.sin_addr.s_addr), 4);
+ }
+
+ // analysis end, begin pack to java
+ if (SOCK_STREAM == opt) {
+ if (remote_addr.sin_port!=0) {
+ //socket
+ channel_class = env->FindClass(
+ "org/apache/harmony/nio/internal/SocketChannelImpl");
+ if (NULL == channel_class) {
+ goto clean;
+ }
+
+ channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+ if (NULL == channel_new) {
+ goto clean;
+ }
+ channel_object = env->NewObject(channel_class, channel_new);
+ if (NULL == channel_object) {
+ goto clean;
+ }
+ // new and set FileDescript
+
+ fd_field = env->GetFieldID(channel_class, "fd",
+ "java/io/FielDescriptor");
+ fd_object = env->GetObjectField(channel_object, fd_field);
+ if (NULL == fd_object) {
+ goto clean;
+ }
+
+ jniSetFileDescriptorOfFD(env, fd_object, socket);
+
+ // local port
+ port_field = env->GetFieldID(channel_class, "localPort", "I");
+ env->SetIntField(channel_object, port_field,
+ ntohs(local_addr.sin_port));
+
+ // new and set remote addr
+ addr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ if (NULL == addr_object) {
+ goto clean;
+ }
+ socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+ socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+ "Ljava/net/InetSocketAddress;");
+ socketaddr_object = env->GetObjectField(channel_object,
+ socketaddr_field);
+ if (NULL == socketaddr_object) {
+ goto clean;
+ }
+ addr_field = env->GetFieldID(socketaddr_class, "addr",
+ "Ljava/net/InetAddress;");
+ env->SetObjectField(socketaddr_object, addr_field, addr_object);
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+ env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress,
+ addr_array);
+
+ // localAddr
+ socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+ socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+ "Ljava/net/InetSocketAddress;");
+ socketaddr_object = env->GetObjectField(channel_object,
+ socketaddr_field);
+
+ localAddr_field = env->GetFieldID(channel_class, "localAddress",
+ "Ljava/net/InetAddress;");
+ localAddr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ jfieldID socketaddr_field = env->GetFieldID(channel_class,
+ "connectAddress", "Ljava/net/InetSocketAddress;");
+ jobject socketaddr_object = env->GetObjectField(channel_object,
+ socketaddr_field);
+ env->SetObjectField(socketaddr_object, localAddr_field,
+ localAddr_object);
+ if (NULL == localAddr_object) {
+ goto clean;
+ }
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+ env->SetObjectField(localAddr_object, gCachedFields.iaddr_ipaddress,
+ addr_array);
+
+
+ // set port
+ port_field = env->GetFieldID(socketaddr_class, "port", "I");
+ env->SetIntField(socketaddr_object, port_field,
+ ntohs(remote_addr.sin_port));
+
+ // set bound
+ if (0 != local_addr.sin_port) {
+ bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+ env->SetBooleanField(channel_object, bound_field, jtrue);
+ }
+
+ } else {
+ //serverSocket
+ channel_class = env->FindClass(
+ "org/apache/harmony/nio/internal/ServerSocketChannelImpl");
+ if (NULL == channel_class) {
+ goto clean;
+ }
+
+ channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+ if (NULL == channel_new) {
+ goto clean;
+ }
+ channel_object = env->NewObject(channel_class, channel_new);
+ if (NULL == channel_object) {
+ goto clean;
+ }
+
+ serverSocket_field = env->GetFieldID(channel_class, "socket",
+ "Ljava/net/ServerSocket;");
+ serverSocket_class = env->FindClass("Ljava/net/ServerSocket;");
+ serverSocket_object = env->GetObjectField(channel_object,
+ serverSocket_field);
+ // set bound
+ if (0 != local_addr.sin_port) {
+ bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+ env->SetBooleanField(channel_object, bound_field, jtrue);
+ bound_field = env->GetFieldID(serverSocket_class, "isBound", "Z");
+ env->SetBooleanField(serverSocket_object, bound_field, jtrue);
+ }
+ // localAddr
+ socketImpl_class = env->FindClass("java/net/SocketImpl");
+ socketImpl_field = env->GetFieldID(channel_class, "impl",
+ "Ljava/net/SocketImpl;");
+ socketImpl_object = env->GetObjectField(channel_object,
+ socketImpl_field);
+ if (NULL == socketImpl_object) {
+ goto clean;
+ }
+
+ localAddr_field = env->GetFieldID(channel_class, "localAddress",
+ "Ljava/net/InetAddress;");
+ localAddr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ if (NULL == localAddr_object) {
+ goto clean;
+ }
+ env->SetObjectField(socketImpl_object, localAddr_field,
+ localAddr_object);
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+ env->SetObjectField(localAddr_object,
+ gCachedFields.iaddr_ipaddress, addr_array);
+
+ // set port
+ port_field = env->GetFieldID(socketImpl_class, "localport", "I");
+ env->SetIntField(socketImpl_object, port_field,
+ ntohs(local_addr.sin_port));
+ }
+ } else {
+ //Datagram Socket
+ // new DatagramChannel
+ channel_class = env->FindClass(
+ "org/apache/harmony/nio/internal/DatagramChannelImpl");
+ if (NULL == channel_class) {
+ goto clean;
+ }
+
+ channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+ if (NULL == channel_new) {
+ goto clean;
+ }
+ channel_object = env->NewObject(channel_class, channel_new);
+ if (NULL == channel_object) {
+ goto clean;
+ }
+
+ // new and set FileDescript
+ fd_field = env->GetFieldID(channel_class, "fd", "java/io/FileDescriptor");
+ fd_object = env->GetObjectField(channel_object, fd_field);
+ if (NULL == fd_object) {
+ goto clean;
+ }
+
+ jniSetFileDescriptorOfFD(env, fd_object, socket);
+
+ port_field = env->GetFieldID(channel_class, "localPort", "I");
+ env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
+
+ // new and set remote addr
+ addr_object = env->NewObject(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_class_init);
+ if (NULL == addr_object) {
+ goto clean;
+ }
+ socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+ socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+ "Ljava/net/InetSocketAddress;");
+ socketaddr_object = env->GetObjectField(channel_object, socketaddr_field);
+ if (NULL == socketaddr_object) {
+ goto clean;
+ }
+ addr_field = env->GetFieldID(socketaddr_class, "addr",
+ "Ljava/net/InetAddress;");
+ env->SetObjectField(socketaddr_object, addr_field, addr_object);
+ addr_array = env->NewByteArray((jsize)4);
+ env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+ env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, addr_array);
+
+ // set bound
+ if (0 != local_addr.sin_port) {
+ bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+ env->SetBooleanField(channel_object, bound_field, jtrue);
+ }
+ }
+clean:
+ free(address);
+ free(localAddr);
+ return channel_object;
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "oneTimeInitializationImpl", "(Z)V", (void*) osNetworkSystem_oneTimeInitializationImpl },
+ { "createSocketImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createSocketImpl },
+ { "createDatagramSocketImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createDatagramSocketImpl },
+ { "readSocketImpl", "(Ljava/io/FileDescriptor;[BIII)I", (void*) osNetworkSystem_readSocketImpl },
+ { "readSocketDirectImpl", "(Ljava/io/FileDescriptor;IIII)I", (void*) osNetworkSystem_readSocketDirectImpl },
+ { "writeSocketImpl", "(Ljava/io/FileDescriptor;[BII)I", (void*) osNetworkSystem_writeSocketImpl },
+ { "writeSocketDirectImpl", "(Ljava/io/FileDescriptor;III)I", (void*) osNetworkSystem_writeSocketDirectImpl },
+ { "setNonBlockingImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_setNonBlockingImpl },
+ { "connectSocketImpl", "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;I)I", (void*) osNetworkSystem_connectSocketImpl },
+ { "connectWithTimeoutSocketImpl", "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;II[B)I", (void*) osNetworkSystem_connectWithTimeoutSocketImpl },
+ { "connectStreamWithTimeoutSocketImpl","(Ljava/io/FileDescriptor;IIILjava/net/InetAddress;)V", (void*) osNetworkSystem_connectStreamWithTimeoutSocketImpl },
+ { "socketBindImpl", "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;)V", (void*) osNetworkSystem_socketBindImpl },
+ { "listenStreamSocketImpl", "(Ljava/io/FileDescriptor;I)V", (void*) osNetworkSystem_listenStreamSocketImpl },
+ { "availableStreamImpl", "(Ljava/io/FileDescriptor;)I", (void*) osNetworkSystem_availableStreamImpl },
+ { "acceptSocketImpl", "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;I)V",(void*) osNetworkSystem_acceptSocketImpl },
+ { "supportsUrgentDataImpl", "(Ljava/io/FileDescriptor;)Z", (void*) osNetworkSystem_supportsUrgentDataImpl },
+ { "sendUrgentDataImpl", "(Ljava/io/FileDescriptor;B)V", (void*) osNetworkSystem_sendUrgentDataImpl },
+ { "connectDatagramImpl2", "(Ljava/io/FileDescriptor;IILjava/net/InetAddress;)V", (void*) osNetworkSystem_connectDatagramImpl2 },
+ { "disconnectDatagramImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_disconnectDatagramImpl },
+ { "socketBindImpl2", "(Ljava/io/FileDescriptor;IZLjava/net/InetAddress;)Z", (void*) osNetworkSystem_socketBindImpl2 },
+ { "peekDatagramImpl", "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)I", (void*) osNetworkSystem_peekDatagramImpl },
+ { "receiveDatagramImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I", (void*) osNetworkSystem_receiveDatagramImpl },
+ { "receiveDatagramDirectImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I", (void*) osNetworkSystem_receiveDatagramDirectImpl },
+ { "recvConnectedDatagramImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;[BIIIZ)I", (void*) osNetworkSystem_recvConnectedDatagramImpl },
+ { "recvConnectedDatagramDirectImpl", "(Ljava/io/FileDescriptor;Ljava/net/DatagramPacket;IIIIZ)I", (void*) osNetworkSystem_recvConnectedDatagramDirectImpl },
+ { "sendDatagramImpl", "(Ljava/io/FileDescriptor;[BIIIZILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagramImpl },
+ { "sendDatagramDirectImpl", "(Ljava/io/FileDescriptor;IIIIZILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagramDirectImpl },
+ { "sendConnectedDatagramImpl", "(Ljava/io/FileDescriptor;[BIIZ)I", (void*) osNetworkSystem_sendConnectedDatagramImpl },
+ { "sendConnectedDatagramDirectImpl", "(Ljava/io/FileDescriptor;IIIZ)I", (void*) osNetworkSystem_sendConnectedDatagramDirectImpl },
+ { "createServerStreamSocketImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createServerStreamSocketImpl },
+ { "createMulticastSocketImpl", "(Ljava/io/FileDescriptor;Z)V", (void*) osNetworkSystem_createMulticastSocketImpl },
+ { "receiveStreamImpl", "(Ljava/io/FileDescriptor;[BIII)I", (void*) osNetworkSystem_receiveStreamImpl },
+ { "sendStreamImpl", "(Ljava/io/FileDescriptor;[BII)I", (void*) osNetworkSystem_sendStreamImpl },
+ { "shutdownInputImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_shutdownInputImpl },
+ { "shutdownOutputImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_shutdownOutputImpl },
+ { "sendDatagramImpl2", "(Ljava/io/FileDescriptor;[BIIILjava/net/InetAddress;)I", (void*) osNetworkSystem_sendDatagramImpl2 },
+ { "selectImpl", "([Ljava/io/FileDescriptor;[Ljava/io/FileDescriptor;II[IJ)I", (void*) osNetworkSystem_selectImpl },
+ { "getSocketLocalAddressImpl", "(Ljava/io/FileDescriptor;Z)Ljava/net/InetAddress;", (void*) osNetworkSystem_getSocketLocalAddressImpl },
+ { "getSocketLocalPortImpl", "(Ljava/io/FileDescriptor;Z)I", (void*) osNetworkSystem_getSocketLocalPortImpl },
+ { "getSocketOptionImpl", "(Ljava/io/FileDescriptor;I)Ljava/lang/Object;", (void*) osNetworkSystem_getSocketOptionImpl },
+ { "setSocketOptionImpl", "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V", (void*) osNetworkSystem_setSocketOptionImpl },
+ { "getSocketFlagsImpl", "()I", (void*) osNetworkSystem_getSocketFlagsImpl },
+ { "socketCloseImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_socketCloseImpl },
+ { "getHostByAddrImpl", "([B)Ljava/net/InetAddress;", (void*) osNetworkSystem_getHostByAddrImpl },
+ { "getHostByNameImpl", "(Ljava/lang/String;Z)Ljava/net/InetAddress;", (void*) osNetworkSystem_getHostByNameImpl },
+ { "setInetAddressImpl", "(Ljava/net/InetAddress;[B)V", (void*) osNetworkSystem_setInetAddressImpl },
+ { "inheritedChannelImpl", "()Ljava/nio/channels/Channel;", (void*) osNetworkSystem_inheritedChannelImpl },
+};
+
+int register_org_apache_harmony_luni_platform_OSNetworkSystem(JNIEnv* env) {
+ return jniRegisterNativeMethods(env,
+ "org/apache/harmony/luni/platform/OSNetworkSystem",
+ gMethods,
+ NELEM(gMethods));
+}
diff --git a/luni/src/main/native/org_apache_harmony_luni_util_NumberConvert.c b/luni/src/main/native/org_apache_harmony_luni_util_NumberConvert.c
new file mode 100644
index 0000000..70761fb
--- /dev/null
+++ b/luni/src/main/native/org_apache_harmony_luni_util_NumberConvert.c
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "JNIHelp.h"
+#include "cbigint.h"
+
+#if defined(LINUX) || defined(FREEBSD)
+#define USE_LL
+#endif
+
+JNIEXPORT void JNICALL
+Java_org_apache_harmony_luni_util_NumberConverter_bigIntDigitGeneratorInstImpl (JNIEnv *
+ env,
+ jobject
+ inst,
+ jlong f,
+ jint e,
+ jboolean
+ isDenormalized,
+ jboolean
+ mantissaIsZero,
+ jint p);
+
+
+#define INV_LOG_OF_TEN_BASE_2 (0.30102999566398114) /* Local */
+#define ERROR_OCCURED(x) (HIGH_I32_FROM_VAR(x) < 0) /* Local */
+
+/*NB the Number converter methods are synchronized so it is possible to
+ *have global data for use by bigIntDigitGenerator */
+#define RM_SIZE 21 /* Local. */
+#define STemp_SIZE 22 /* Local. */
+
+#if defined(WIN32)
+#pragma optimize("",on) /*restore optimizations */
+#endif
+
+/* The algorithm for this particular function can be found in:
+ *
+ * Printing Floating-Point Numbers Quickly and Accurately, Robert
+ * G. Burger, and R. Kent Dybvig, Programming Language Design and
+ * Implementation (PLDI) 1996, pp.108-116.
+ *
+ * The previous implementation of this function combined m+ and m- into
+ * one single M which caused some inaccuracy of the last digit. The
+ * particular case below shows this inaccuracy:
+ *
+ * System.out.println(new Double((1.234123412431233E107)).toString());
+ * System.out.println(new Double((1.2341234124312331E107)).toString());
+ * System.out.println(new Double((1.2341234124312332E107)).toString());
+ *
+ * outputs the following:
+ *
+ * 1.234123412431233E107
+ * 1.234123412431233E107
+ * 1.234123412431233E107
+ *
+ * instead of:
+ *
+ * 1.234123412431233E107
+ * 1.2341234124312331E107
+ * 1.2341234124312331E107
+ *
+ */
+JNIEXPORT void JNICALL
+Java_org_apache_harmony_luni_util_NumberConverter_bigIntDigitGeneratorInstImpl (JNIEnv *
+ env,
+ jobject
+ inst,
+ jlong f,
+ jint e,
+ jboolean
+ isDenormalized,
+ jboolean
+ mantissaIsZero,
+ jint p)
+{
+ int RLength, SLength, TempLength, mplus_Length, mminus_Length;
+ int high, low, i;
+ jint k, firstK, U;
+ jint getCount, setCount;
+ jint *uArray;
+
+ jclass clazz;
+ jfieldID fid;
+ jintArray uArrayObject;
+
+ U_64 R[RM_SIZE], S[STemp_SIZE], mplus[RM_SIZE], mminus[RM_SIZE],
+ Temp[STemp_SIZE];
+
+ memset (R , 0, RM_SIZE * sizeof (U_64));
+ memset (S , 0, STemp_SIZE * sizeof (U_64));
+ memset (mplus , 0, RM_SIZE * sizeof (U_64));
+ memset (mminus, 0, RM_SIZE * sizeof (U_64));
+ memset (Temp , 0, STemp_SIZE * sizeof (U_64));
+
+ if (e >= 0)
+ {
+ *R = f;
+ *mplus = *mminus = 1;
+ simpleShiftLeftHighPrecision (mminus, RM_SIZE, e);
+ if (f != (2 << (p - 1)))
+ {
+ simpleShiftLeftHighPrecision (R, RM_SIZE, e + 1);
+ *S = 2;
+ /*
+ * m+ = m+ << e results in 1.0e23 to be printed as
+ * 0.9999999999999999E23
+ * m+ = m+ << e+1 results in 1.0e23 to be printed as
+ * 1.0e23 (caused too much rounding)
+ * 470fffffffffffff = 2.0769187434139308E34
+ * 4710000000000000 = 2.076918743413931E34
+ */
+ simpleShiftLeftHighPrecision (mplus, RM_SIZE, e);
+ }
+ else
+ {
+ simpleShiftLeftHighPrecision (R, RM_SIZE, e + 2);
+ *S = 4;
+ simpleShiftLeftHighPrecision (mplus, RM_SIZE, e + 1);
+ }
+ }
+ else
+ {
+ if (isDenormalized || (f != (2 << (p - 1))))
+ {
+ *R = f << 1;
+ *S = 1;
+ simpleShiftLeftHighPrecision (S, STemp_SIZE, 1 - e);
+ *mplus = *mminus = 1;
+ }
+ else
+ {
+ *R = f << 2;
+ *S = 1;
+ simpleShiftLeftHighPrecision (S, STemp_SIZE, 2 - e);
+ *mplus = 2;
+ *mminus = 1;
+ }
+ }
+
+ k = (int) ceil ((e + p - 1) * INV_LOG_OF_TEN_BASE_2 - 1e-10);
+
+ if (k > 0)
+ {
+ timesTenToTheEHighPrecision (S, STemp_SIZE, k);
+ }
+ else
+ {
+ timesTenToTheEHighPrecision (R , RM_SIZE, -k);
+ timesTenToTheEHighPrecision (mplus , RM_SIZE, -k);
+ timesTenToTheEHighPrecision (mminus, RM_SIZE, -k);
+ }
+
+ RLength = mplus_Length = mminus_Length = RM_SIZE;
+ SLength = TempLength = STemp_SIZE;
+
+ memset (Temp + RM_SIZE, 0, (STemp_SIZE - RM_SIZE) * sizeof (U_64));
+ memcpy (Temp, R, RM_SIZE * sizeof (U_64));
+
+ while (RLength > 1 && R[RLength - 1] == 0)
+ --RLength;
+ while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
+ --mplus_Length;
+ while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
+ --mminus_Length;
+ while (SLength > 1 && S[SLength - 1] == 0)
+ --SLength;
+ TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1;
+ addHighPrecision (Temp, TempLength, mplus, mplus_Length);
+
+ if (compareHighPrecision (Temp, TempLength, S, SLength) >= 0)
+ {
+ firstK = k;
+ }
+ else
+ {
+ firstK = k - 1;
+ simpleAppendDecimalDigitHighPrecision (R , ++RLength , 0);
+ simpleAppendDecimalDigitHighPrecision (mplus , ++mplus_Length , 0);
+ simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0);
+ while (RLength > 1 && R[RLength - 1] == 0)
+ --RLength;
+ while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
+ --mplus_Length;
+ while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
+ --mminus_Length;
+ }
+
+ clazz = (*env)->GetObjectClass (env, inst);
+ fid = (*env)->GetFieldID (env, clazz, "uArray", "[I");
+ uArrayObject = (jintArray) (*env)->GetObjectField (env, inst, fid);
+ uArray = (*env)->GetIntArrayElements (env, uArrayObject, 0);
+
+ getCount = setCount = 0;
+ do
+ {
+ U = 0;
+ for (i = 3; i >= 0; --i)
+ {
+ TempLength = SLength + 1;
+ Temp[SLength] = 0;
+ memcpy (Temp, S, SLength * sizeof (U_64));
+ simpleShiftLeftHighPrecision (Temp, TempLength, i);
+ if (compareHighPrecision (R, RLength, Temp, TempLength) >= 0)
+ {
+ subtractHighPrecision (R, RLength, Temp, TempLength);
+ U += 1 << i;
+ }
+ }
+
+ low = compareHighPrecision (R, RLength, mminus, mminus_Length) <= 0;
+
+ memset (Temp + RLength, 0, (STemp_SIZE - RLength) * sizeof (U_64));
+ memcpy (Temp, R, RLength * sizeof (U_64));
+ TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1;
+ addHighPrecision (Temp, TempLength, mplus, mplus_Length);
+
+ high = compareHighPrecision (Temp, TempLength, S, SLength) >= 0;
+
+ if (low || high)
+ break;
+
+ simpleAppendDecimalDigitHighPrecision (R , ++RLength , 0);
+ simpleAppendDecimalDigitHighPrecision (mplus , ++mplus_Length , 0);
+ simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0);
+ while (RLength > 1 && R[RLength - 1] == 0)
+ --RLength;
+ while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
+ --mplus_Length;
+ while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
+ --mminus_Length;
+ uArray[setCount++] = U;
+ }
+ while (1);
+
+ simpleShiftLeftHighPrecision (R, ++RLength, 1);
+ if (low && !high)
+ uArray[setCount++] = U;
+ else if (high && !low)
+ uArray[setCount++] = U + 1;
+ else if (compareHighPrecision (R, RLength, S, SLength) < 0)
+ uArray[setCount++] = U;
+ else
+ uArray[setCount++] = U + 1;
+
+ (*env)->ReleaseIntArrayElements (env, uArrayObject, uArray, 0);
+
+ fid = (*env)->GetFieldID (env, clazz, "setCount", "I");
+ (*env)->SetIntField (env, inst, fid, setCount);
+
+ fid = (*env)->GetFieldID (env, clazz, "getCount", "I");
+ (*env)->SetIntField (env, inst, fid, getCount);
+
+ fid = (*env)->GetFieldID (env, clazz, "firstK", "I");
+ (*env)->SetIntField (env, inst, fid, firstK);
+
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* NAME, SIGNATURE, FUNCPTR */
+ { "bigIntDigitGeneratorInstImpl", "(JIZZI)V" ,
+ Java_org_apache_harmony_luni_util_NumberConverter_bigIntDigitGeneratorInstImpl },
+};
+
+int register_org_apache_harmony_luni_util_NumberConvert(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env,
+ "org/apache/harmony/luni/util/NumberConverter",
+ gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/org_apache_harmony_luni_util_fltparse.c b/luni/src/main/native/org_apache_harmony_luni_util_fltparse.c
new file mode 100644
index 0000000..d8a1e68
--- /dev/null
+++ b/luni/src/main/native/org_apache_harmony_luni_util_fltparse.c
@@ -0,0 +1,609 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "JNIHelp.h"
+#include "commonDblParce.h"
+#include "cbigint.h"
+
+#if defined(LINUX)
+#define USE_LL
+#endif
+
+#define LOW_I32_FROM_VAR(u64) LOW_I32_FROM_LONG64(u64)
+#ifdef HY_LITTLE_ENDIAN
+#define LOW_I32_FROM_PTR(ptr64) (*(I_32 *) (ptr64))
+#else
+#define LOW_I32_FROM_PTR(ptr64) (*(((I_32 *) (ptr64)) + 1))
+#endif
+#define HIGH_I32_FROM_VAR(u64) HIGH_I32_FROM_LONG64(u64)
+#define HIGH_I32_FROM_PTR(u64ptr) HIGH_I32_FROM_LONG64_PTR(u64ptr)
+
+#define MAX_ACCURACY_WIDTH 8
+
+#define DEFAULT_WIDTH MAX_ACCURACY_WIDTH
+
+JNIEXPORT jfloat JNICALL
+Java_org_apache_harmony_luni_util_FloatingPointParser_parseFltImpl (JNIEnv * env,
+ jclass clazz,
+ jstring s, jint e);
+JNIEXPORT jdouble JNICALL
+Java_org_apache_harmony_luni_util_FloatingPointParser_parseDblImpl (JNIEnv * env,
+ jclass clazz,
+ jstring s, jint e);
+
+jfloat createFloat1 (JNIEnv * env, U_64 * f, IDATA length, jint e);
+jfloat floatAlgorithm (JNIEnv * env, U_64 * f, IDATA length, jint e,
+ jfloat z);
+jfloat createFloat (JNIEnv * env, const char *s, jint e);
+
+static const U_32 tens[] = {
+ 0x3f800000,
+ 0x41200000,
+ 0x42c80000,
+ 0x447a0000,
+ 0x461c4000,
+ 0x47c35000,
+ 0x49742400,
+ 0x4b189680,
+ 0x4cbebc20,
+ 0x4e6e6b28,
+ 0x501502f9 /* 10 ^ 10 in float */
+};
+
+#define tenToTheE(e) (*((jfloat *) (tens + (e))))
+#define LOG5_OF_TWO_TO_THE_N 11
+
+#define sizeOfTenToTheE(e) (((e) / 19) + 1)
+
+#define INFINITE_INTBITS (0x7F800000)
+#define MINIMUM_INTBITS (1)
+
+#define MANTISSA_MASK (0x007FFFFF)
+#define EXPONENT_MASK (0x7F800000)
+#define NORMAL_MASK (0x00800000)
+#define FLOAT_TO_INTBITS(flt) (*((U_32 *)(&flt)))
+
+/* Keep a count of the number of times we decrement and increment to
+ * approximate the double, and attempt to detect the case where we
+ * could potentially toggle back and forth between decrementing and
+ * incrementing. It is possible for us to be stuck in the loop when
+ * incrementing by one or decrementing by one may exceed or stay below
+ * the value that we are looking for. In this case, just break out of
+ * the loop if we toggle between incrementing and decrementing for more
+ * than twice.
+ */
+#define INCREMENT_FLOAT(_x, _decCount, _incCount) \
+ { \
+ ++FLOAT_TO_INTBITS(_x); \
+ _incCount++; \
+ if( (_incCount > 2) && (_decCount > 2) ) { \
+ if( _decCount > _incCount ) { \
+ FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
+ } else if( _incCount > _decCount ) { \
+ FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
+ } \
+ break; \
+ } \
+ }
+#define DECREMENT_FLOAT(_x, _decCount, _incCount) \
+ { \
+ --FLOAT_TO_INTBITS(_x); \
+ _decCount++; \
+ if( (_incCount > 2) && (_decCount > 2) ) { \
+ if( _decCount > _incCount ) { \
+ FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
+ } else if( _incCount > _decCount ) { \
+ FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
+ } \
+ break; \
+ } \
+ }
+#define ERROR_OCCURED(x) (HIGH_I32_FROM_VAR(x) < 0)
+
+#define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory;
+#define release(r) if ((r)) free((r));
+
+jfloat
+createFloat (JNIEnv * env, const char *s, jint e)
+{
+ /* assumes s is a null terminated string with at least one
+ * character in it */
+ U_64 def[DEFAULT_WIDTH];
+ U_64 defBackup[DEFAULT_WIDTH];
+ U_64 *f, *fNoOverflow, *g, *tempBackup;
+ U_32 overflow;
+ jfloat result;
+ IDATA index = 1;
+ int unprocessedDigits = 0;
+
+ f = def;
+ fNoOverflow = defBackup;
+ *f = 0;
+ tempBackup = g = 0;
+ do
+ {
+ if (*s >= '0' && *s <= '9')
+ {
+ /* Make a back up of f before appending, so that we can
+ * back out of it if there is no more room, i.e. index >
+ * MAX_ACCURACY_WIDTH.
+ */
+ memcpy (fNoOverflow, f, sizeof (U_64) * index);
+ overflow =
+ simpleAppendDecimalDigitHighPrecision (f, index, *s - '0');
+ if (overflow)
+ {
+
+ f[index++] = overflow;
+ /* There is an overflow, but there is no more room
+ * to store the result. We really only need the top 52
+ * bits anyway, so we must back out of the overflow,
+ * and ignore the rest of the string.
+ */
+ if (index >= MAX_ACCURACY_WIDTH)
+ {
+ index--;
+ memcpy (f, fNoOverflow, sizeof (U_64) * index);
+ break;
+ }
+ if (tempBackup)
+ {
+ fNoOverflow = tempBackup;
+ }
+ }
+ }
+ else
+ index = -1;
+ }
+ while (index > 0 && *(++s) != '\0');
+
+ /* We've broken out of the parse loop either because we've reached
+ * the end of the string or we've overflowed the maximum accuracy
+ * limit of a double. If we still have unprocessed digits in the
+ * given string, then there are three possible results:
+ * 1. (unprocessed digits + e) == 0, in which case we simply
+ * convert the existing bits that are already parsed
+ * 2. (unprocessed digits + e) < 0, in which case we simply
+ * convert the existing bits that are already parsed along
+ * with the given e
+ * 3. (unprocessed digits + e) > 0 indicates that the value is
+ * simply too big to be stored as a double, so return Infinity
+ */
+ if ((unprocessedDigits = strlen (s)) > 0)
+ {
+ e += unprocessedDigits;
+ if (index > -1)
+ {
+ if (e <= 0)
+ {
+ result = createFloat1 (env, f, index, e);
+ }
+ else
+ {
+ FLOAT_TO_INTBITS (result) = INFINITE_INTBITS;
+ }
+ }
+ else
+ {
+ result = *(jfloat *) & index;
+ }
+ }
+ else
+ {
+ if (index > -1)
+ {
+ result = createFloat1 (env, f, index, e);
+ }
+ else
+ {
+ result = *(jfloat *) & index;
+ }
+ }
+
+ return result;
+
+}
+
+jfloat
+createFloat1 (JNIEnv * env, U_64 * f, IDATA length, jint e)
+{
+ IDATA numBits;
+ jdouble dresult;
+ jfloat result;
+
+ numBits = highestSetBitHighPrecision (f, length) + 1;
+ numBits -= lowestSetBitHighPrecision (f, length);
+ if (numBits < 25 && e >= 0 && e < LOG5_OF_TWO_TO_THE_N)
+ {
+ return ((jfloat) LOW_I32_FROM_PTR (f)) * tenToTheE (e);
+ }
+ else if (numBits < 25 && e < 0 && (-e) < LOG5_OF_TWO_TO_THE_N)
+ {
+ return ((jfloat) LOW_I32_FROM_PTR (f)) / tenToTheE (-e);
+ }
+ else if (e >= 0 && e < 39)
+ {
+ result = (jfloat) (toDoubleHighPrecision (f, length) * pow (10.0, e));
+ }
+ else if (e >= 39)
+ {
+ /* Convert the partial result to make sure that the
+ * non-exponential part is not zero. This check fixes the case
+ * where the user enters 0.0e309! */
+ result = (jfloat) toDoubleHighPrecision (f, length);
+
+ if (result == 0.0)
+
+ FLOAT_TO_INTBITS (result) = MINIMUM_INTBITS;
+ else
+ FLOAT_TO_INTBITS (result) = INFINITE_INTBITS;
+ }
+ else if (e > -309)
+ {
+ int dexp;
+ U_32 fmant, fovfl;
+ U_64 dmant;
+ dresult = toDoubleHighPrecision (f, length) / pow (10.0, -e);
+ if (IS_DENORMAL_DBL (dresult))
+ {
+ FLOAT_TO_INTBITS (result) = 0;
+ return result;
+ }
+ dexp = doubleExponent (dresult) + 51;
+ dmant = doubleMantissa (dresult);
+ /* Is it too small to be represented by a single-precision
+ * float? */
+ if (dexp <= -155)
+ {
+ FLOAT_TO_INTBITS (result) = 0;
+ return result;
+ }
+ /* Is it a denormalized single-precision float? */
+ if ((dexp <= -127) && (dexp > -155))
+ {
+ /* Only interested in 24 msb bits of the 53-bit double mantissa */
+ fmant = (U_32) (dmant >> 29);
+ fovfl = ((U_32) (dmant & 0x1FFFFFFF)) << 3;
+ while ((dexp < -127) && ((fmant | fovfl) != 0))
+ {
+ if ((fmant & 1) != 0)
+ {
+ fovfl |= 0x80000000;
+ }
+ fovfl >>= 1;
+ fmant >>= 1;
+ dexp++;
+ }
+ if ((fovfl & 0x80000000) != 0)
+ {
+ if ((fovfl & 0x7FFFFFFC) != 0)
+ {
+ fmant++;
+ }
+ else if ((fmant & 1) != 0)
+ {
+ fmant++;
+ }
+ }
+ else if ((fovfl & 0x40000000) != 0)
+ {
+ if ((fovfl & 0x3FFFFFFC) != 0)
+ {
+ fmant++;
+ }
+ }
+ FLOAT_TO_INTBITS (result) = fmant;
+ }
+ else
+ {
+ result = (jfloat) dresult;
+ }
+ }
+
+ /* Don't go straight to zero as the fact that x*0 = 0 independent
+ * of x might cause the algorithm to produce an incorrect result.
+ * Instead try the min value first and let it fall to zero if need
+ * be.
+ */
+ if (e <= -309 || FLOAT_TO_INTBITS (result) == 0)
+ FLOAT_TO_INTBITS (result) = MINIMUM_INTBITS;
+
+ return floatAlgorithm (env, f, length, e, (jfloat) result);
+}
+
+#if defined(WIN32)
+/* disable global optimizations on the microsoft compiler for the
+ * floatAlgorithm function otherwise it won't properly compile */
+#pragma optimize("g",off)
+#endif
+
+/* The algorithm for the function floatAlgorithm() below can be found
+ * in:
+ *
+ * "How to Read Floating-Point Numbers Accurately", William D.
+ * Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
+ * Programming Language Design and Implementation, June 20-22,
+ * 1990, pp. 92-101.
+ *
+ * There is a possibility that the function will end up in an endless
+ * loop if the given approximating floating-point number (a very small
+ * floating-point whose value is very close to zero) straddles between
+ * two approximating integer values. We modified the algorithm slightly
+ * to detect the case where it oscillates back and forth between
+ * incrementing and decrementing the floating-point approximation. It
+ * is currently set such that if the oscillation occurs more than twice
+ * then return the original approximation.
+ */
+jfloat
+floatAlgorithm (JNIEnv * env, U_64 * f, IDATA length, jint e, jfloat z)
+{
+ U_64 m;
+ IDATA k, comparison, comparison2;
+ U_64 *x, *y, *D, *D2;
+ IDATA xLength, yLength, DLength, D2Length;
+ IDATA decApproxCount, incApproxCount;
+
+ x = y = D = D2 = 0;
+ xLength = yLength = DLength = D2Length = 0;
+ decApproxCount = incApproxCount = 0;
+
+ do
+ {
+ m = floatMantissa (z);
+ k = floatExponent (z);
+
+ if (x && x != f)
+ free(x);
+
+ release (y);
+ release (D);
+ release (D2);
+
+ if (e >= 0 && k >= 0)
+ {
+ xLength = sizeOfTenToTheE (e) + length;
+ allocateU64 (x, xLength);
+ memset (x + length, 0, sizeof (U_64) * (xLength - length));
+ memcpy (x, f, sizeof (U_64) * length);
+ timesTenToTheEHighPrecision (x, xLength, e);
+
+ yLength = (k >> 6) + 2;
+ allocateU64 (y, yLength);
+ memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
+ *y = m;
+ simpleShiftLeftHighPrecision (y, yLength, k);
+ }
+ else if (e >= 0)
+ {
+ xLength = sizeOfTenToTheE (e) + length + ((-k) >> 6) + 1;
+ allocateU64 (x, xLength);
+ memset (x + length, 0, sizeof (U_64) * (xLength - length));
+ memcpy (x, f, sizeof (U_64) * length);
+ timesTenToTheEHighPrecision (x, xLength, e);
+ simpleShiftLeftHighPrecision (x, xLength, -k);
+
+ yLength = 1;
+ allocateU64 (y, 1);
+ *y = m;
+ }
+ else if (k >= 0)
+ {
+ xLength = length;
+ x = f;
+
+ yLength = sizeOfTenToTheE (-e) + 2 + (k >> 6);
+ allocateU64 (y, yLength);
+ memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
+ *y = m;
+ timesTenToTheEHighPrecision (y, yLength, -e);
+ simpleShiftLeftHighPrecision (y, yLength, k);
+ }
+ else
+ {
+ xLength = length + ((-k) >> 6) + 1;
+ allocateU64 (x, xLength);
+ memset (x + length, 0, sizeof (U_64) * (xLength - length));
+ memcpy (x, f, sizeof (U_64) * length);
+ simpleShiftLeftHighPrecision (x, xLength, -k);
+
+ yLength = sizeOfTenToTheE (-e) + 1;
+ allocateU64 (y, yLength);
+ memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
+ *y = m;
+ timesTenToTheEHighPrecision (y, yLength, -e);
+ }
+
+ comparison = compareHighPrecision (x, xLength, y, yLength);
+ if (comparison > 0)
+ { /* x > y */
+ DLength = xLength;
+ allocateU64 (D, DLength);
+ memcpy (D, x, DLength * sizeof (U_64));
+ subtractHighPrecision (D, DLength, y, yLength);
+ }
+ else if (comparison)
+ { /* y > x */
+ DLength = yLength;
+ allocateU64 (D, DLength);
+ memcpy (D, y, DLength * sizeof (U_64));
+ subtractHighPrecision (D, DLength, x, xLength);
+ }
+ else
+ { /* y == x */
+ DLength = 1;
+ allocateU64 (D, 1);
+ *D = 0;
+ }
+
+ D2Length = DLength + 1;
+ allocateU64 (D2, D2Length);
+ m <<= 1;
+ multiplyHighPrecision (D, DLength, &m, 1, D2, D2Length);
+ m >>= 1;
+
+ comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
+ if (comparison2 < 0)
+ {
+ if (comparison < 0 && m == NORMAL_MASK)
+ {
+ simpleShiftLeftHighPrecision (D2, D2Length, 1);
+ if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
+ {
+ DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else if (comparison2 == 0)
+ {
+ if ((m & 1) == 0)
+ {
+ if (comparison < 0 && m == NORMAL_MASK)
+ {
+ DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else if (comparison < 0)
+ {
+ DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ break;
+ }
+ else
+ {
+ INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ break;
+ }
+ }
+ else if (comparison < 0)
+ {
+ DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ }
+ else
+ {
+ if (FLOAT_TO_INTBITS (z) == EXPONENT_MASK)
+ break;
+ INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
+ }
+ }
+ while (1);
+
+ if (x && x != f)
+ free(x);
+ release (y);
+ release (D);
+ release (D2);
+ return z;
+
+OutOfMemory:
+ if (x && x != f)
+ free(x);
+ release (y);
+ release (D);
+ release (D2);
+
+ FLOAT_TO_INTBITS (z) = -2;
+
+ return z;
+}
+
+#if defined(WIN32)
+#pragma optimize("",on) /*restore optimizations */
+#endif
+
+JNIEXPORT jfloat JNICALL
+Java_org_apache_harmony_luni_util_FloatingPointParser_parseFltImpl (JNIEnv * env,
+ jclass clazz,
+ jstring s, jint e)
+{
+ jfloat flt;
+ const char *str = (*env)->GetStringUTFChars (env, s, 0);
+ flt = createFloat (env, str, e);
+ (*env)->ReleaseStringUTFChars (env, s, str);
+
+ if (((I_32) FLOAT_TO_INTBITS (flt)) >= 0)
+ {
+ return flt;
+ }
+ else if (((I_32) FLOAT_TO_INTBITS (flt)) == (I_32) - 1)
+ { /* NumberFormatException */
+ jniThrowException(env, "java/lang/NumberFormatException", "");
+ }
+ else
+ { /* OutOfMemoryError */
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
+ }
+
+ return 0.0;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_org_apache_harmony_luni_util_FloatingPointParser_parseDblImpl (JNIEnv * env,
+ jclass clazz,
+ jstring s, jint e)
+{
+ jdouble dbl;
+ const char *str = (*env)->GetStringUTFChars (env, s, 0);
+ dbl = createDouble (env, str, e);
+ (*env)->ReleaseStringUTFChars (env, s, str);
+
+ if (!ERROR_OCCURED (dbl))
+ {
+ return dbl;
+ }
+ else if (LOW_I32_FROM_VAR (dbl) == (I_32) - 1)
+ { /* NumberFormatException */
+ jniThrowException(env, "java/lang/NumberFormatException", "");
+ }
+ else
+ { /* OutOfMemoryError */
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
+ }
+
+ return 0.0;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* NAME, SIGNATURE, FUNCPTR */
+ { "parseFltImpl", "(Ljava/lang/String;I)F",
+ Java_org_apache_harmony_luni_util_FloatingPointParser_parseFltImpl },
+ { "parseDblImpl", "(Ljava/lang/String;I)D",
+ Java_org_apache_harmony_luni_util_FloatingPointParser_parseDblImpl },
+};
+int register_org_apache_harmony_luni_util_fltparse(JNIEnv *env)
+{
+ return jniRegisterNativeMethods(env,
+ "org/apache/harmony/luni/util/FloatingPointParser",
+ gMethods, NELEM(gMethods));
+}
+
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
new file mode 100644
index 0000000..d277f82
--- /dev/null
+++ b/luni/src/main/native/sub.mk
@@ -0,0 +1,34 @@
+# This file is included by the top-level libcore Android.mk.
+# It's not a normal makefile, so we don't include CLEAR_VARS
+# or BUILD_*_LIBRARY.
+
+LOCAL_SRC_FILES := \
+ java_io_File.c \
+ java_io_FileDescriptor.c \
+ java_io_ObjectInputStream.c \
+ java_io_ObjectOutputStream.c \
+ java_io_ObjectStreamClass.c \
+ java_lang_Double.c \
+ java_lang_Float.c \
+ java_lang_Math.c \
+ java_lang_StrictMath.c \
+ java_net_InetAddress.cpp \
+ java_net_NetworkInterface.c \
+ cbigint.c \
+ commonDblParce.c \
+ org_apache_harmony_luni_util_fltparse.c \
+ org_apache_harmony_luni_util_NumberConvert.c \
+ org_apache_harmony_luni_platform_OSNetworkSystem.cpp \
+ org_apache_harmony_luni_platform_OSFileSystem.cpp \
+ org_apache_harmony_luni_platform_OSMemory.cpp
+
+LOCAL_C_INCLUDES +=
+
+# Any shared/static libs that are listed here must also
+# be listed in libs/nativehelper/Android.mk.
+# TODO: fix this requirement
+
+LOCAL_SHARED_LIBRARIES += libutils
+
+LOCAL_STATIC_LIBRARIES += \
+ libfdlibm