440 done: |
441 done: |
441 (*env)->DeleteLocalRef(env, cls); |
442 (*env)->DeleteLocalRef(env, cls); |
442 return obj; |
443 return obj; |
443 } |
444 } |
444 |
445 |
445 /* Optimized for char set ISO_8559_1 */ |
446 /* Optimized for charset ISO_8559_1 */ |
446 static jstring |
447 static jstring |
447 newString8859_1(JNIEnv *env, const char *str) |
448 newSizedString8859_1(JNIEnv *env, const char *str, const int len) |
448 { |
449 { |
449 int len = (int)strlen(str); |
|
450 jchar buf[512]; |
450 jchar buf[512]; |
451 jchar *str1; |
451 jchar *str1; |
452 jstring result; |
452 jstring result; |
453 int i; |
453 int i; |
|
454 |
|
455 if ((*env)->EnsureLocalCapacity(env, 1) < 0) |
|
456 return NULL; |
454 |
457 |
455 if (len > 512) { |
458 if (len > 512) { |
456 str1 = (jchar *)malloc(len * sizeof(jchar)); |
459 str1 = (jchar *)malloc(len * sizeof(jchar)); |
457 if (str1 == 0) { |
460 if (str1 == 0) { |
458 JNU_ThrowOutOfMemoryError(env, 0); |
461 JNU_ThrowOutOfMemoryError(env, 0); |
571 0x02C6,0x2030,0x0160,0x2039,0x0152,0xFFFD,0x017D,0xFFFD, |
581 0x02C6,0x2030,0x0160,0x2039,0x0152,0xFFFD,0x017D,0xFFFD, |
572 0xFFFD,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014, |
582 0xFFFD,0x2018,0x2019,0x201C,0x201D,0x2022,0x2013,0x2014, |
573 0x02Dc,0x2122,0x0161,0x203A,0x0153,0xFFFD,0x017E,0x0178 |
583 0x02Dc,0x2122,0x0161,0x203A,0x0153,0xFFFD,0x017E,0x0178 |
574 }; |
584 }; |
575 |
585 |
576 /* Optimized for char set Cp1252 */ |
586 /* Optimized for charset Cp1252 */ |
577 static jstring |
587 static jstring |
578 newStringCp1252(JNIEnv *env, const char *str) |
588 newStringCp1252(JNIEnv *env, const char *str) |
579 { |
589 { |
580 int len = (int) strlen(str); |
590 int len = (int) strlen(str); |
581 jchar buf[512]; |
591 jchar buf[512]; |
582 jchar *str1; |
592 jchar *str1; |
583 jstring result; |
593 jstring result; |
584 int i; |
594 int i; |
|
595 |
|
596 if ((*env)->EnsureLocalCapacity(env, 1) < 0) |
|
597 return NULL; |
|
598 |
585 if (len > 512) { |
599 if (len > 512) { |
586 str1 = (jchar *)malloc(len * sizeof(jchar)); |
600 str1 = (jchar *)malloc(len * sizeof(jchar)); |
587 if (str1 == 0) { |
601 if (str1 == 0) { |
588 JNU_ThrowOutOfMemoryError(env, 0); |
602 JNU_ThrowOutOfMemoryError(env, 0); |
589 return 0; |
603 return 0; |
669 |
687 |
670 /* Cached method IDs */ |
688 /* Cached method IDs */ |
671 static jmethodID String_init_ID; /* String(byte[], enc) */ |
689 static jmethodID String_init_ID; /* String(byte[], enc) */ |
672 static jmethodID String_getBytes_ID; /* String.getBytes(enc) */ |
690 static jmethodID String_getBytes_ID; /* String.getBytes(enc) */ |
673 |
691 |
674 int getFastEncoding() { |
692 /* Cached field IDs */ |
675 return fastEncoding; |
693 static jfieldID String_coder_ID; /* String.coder */ |
|
694 static jfieldID String_value_ID; /* String.value */ |
|
695 |
|
696 static jboolean isJNUEncodingSupported = JNI_FALSE; |
|
697 static jboolean jnuEncodingSupported(JNIEnv *env) { |
|
698 jboolean exe; |
|
699 if (isJNUEncodingSupported == JNI_TRUE) { |
|
700 return JNI_TRUE; |
|
701 } |
|
702 isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName ( |
|
703 env, &exe, |
|
704 "java/nio/charset/Charset", |
|
705 "isSupported", |
|
706 "(Ljava/lang/String;)Z", |
|
707 jnuEncoding).z; |
|
708 return isJNUEncodingSupported; |
|
709 } |
|
710 |
|
711 /* Create a new string by converting str to a heap-allocated byte array and |
|
712 * calling the appropriate String constructor. |
|
713 */ |
|
714 static jstring |
|
715 newSizedStringJava(JNIEnv *env, const char *str, const int len) |
|
716 { |
|
717 jstring result = NULL; |
|
718 jbyteArray bytes = 0; |
|
719 |
|
720 if ((*env)->EnsureLocalCapacity(env, 2) < 0) |
|
721 return NULL; |
|
722 |
|
723 bytes = (*env)->NewByteArray(env, len); |
|
724 if (bytes != NULL) { |
|
725 jclass strClazz = JNU_ClassString(env); |
|
726 CHECK_NULL_RETURN(strClazz, 0); |
|
727 (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *)str); |
|
728 if (jnuEncodingSupported(env)) { |
|
729 result = (*env)->NewObject(env, strClazz, |
|
730 String_init_ID, bytes, jnuEncoding); |
|
731 } else { |
|
732 /*If the encoding specified in sun.jnu.encoding is not endorsed |
|
733 by "Charset.isSupported" we have to fall back to use String(byte[]) |
|
734 explicitly here without specifying the encoding name, in which the |
|
735 StringCoding class will pickup the iso-8859-1 as the fallback |
|
736 converter for us. |
|
737 */ |
|
738 jmethodID mid = (*env)->GetMethodID(env, strClazz, |
|
739 "<init>", "([B)V"); |
|
740 if (mid != NULL) { |
|
741 result = (*env)->NewObject(env, strClazz, mid, bytes); |
|
742 } |
|
743 } |
|
744 (*env)->DeleteLocalRef(env, bytes); |
|
745 return result; |
|
746 } |
|
747 return NULL; |
|
748 } |
|
749 |
|
750 static jstring |
|
751 newStringJava(JNIEnv *env, const char *str) |
|
752 { |
|
753 int len = (int)strlen(str); |
|
754 return newSizedStringJava(env, str, len); |
|
755 } |
|
756 |
|
757 /* Optimized for charset UTF-8 */ |
|
758 static jstring |
|
759 newStringUTF8(JNIEnv *env, const char *str) |
|
760 { |
|
761 int len; |
|
762 const unsigned char *p; |
|
763 unsigned char asciiCheck; |
|
764 for (asciiCheck = 0, p = (const unsigned char*)str; *p != '\0'; p++) { |
|
765 asciiCheck |= *p; |
|
766 } |
|
767 len = (int)((const char*)p - str); |
|
768 |
|
769 if (asciiCheck < 0x80) { |
|
770 // ascii fast-path |
|
771 return newSizedString8859_1(env, str, len); |
|
772 } |
|
773 |
|
774 return newSizedStringJava(env, str, len); |
676 } |
775 } |
677 |
776 |
678 /* Initialize the fast encoding. If the "sun.jnu.encoding" property |
777 /* Initialize the fast encoding. If the "sun.jnu.encoding" property |
679 * has not yet been set, we leave fastEncoding == NO_ENCODING_YET. |
778 * has not yet been set, we leave fastEncoding == NO_ENCODING_YET. |
680 */ |
779 */ |
716 * "en_UK" locale -> "ISO8859-1" (on 2.6) |
815 * "en_UK" locale -> "ISO8859-1" (on 2.6) |
717 */ |
816 */ |
718 if ((strcmp(encname, "8859_1") == 0) || |
817 if ((strcmp(encname, "8859_1") == 0) || |
719 (strcmp(encname, "ISO8859-1") == 0) || |
818 (strcmp(encname, "ISO8859-1") == 0) || |
720 (strcmp(encname, "ISO8859_1") == 0) || |
819 (strcmp(encname, "ISO8859_1") == 0) || |
721 (strcmp(encname, "ISO-8859-1") == 0)) |
820 (strcmp(encname, "ISO-8859-1") == 0)) { |
722 fastEncoding = FAST_8859_1; |
821 fastEncoding = FAST_8859_1; |
723 else if (strcmp(encname, "ISO646-US") == 0) |
822 } else if (strcmp(encname, "UTF-8") == 0) { |
|
823 fastEncoding = FAST_UTF_8; |
|
824 jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc); |
|
825 } else if (strcmp(encname, "ISO646-US") == 0) { |
724 fastEncoding = FAST_646_US; |
826 fastEncoding = FAST_646_US; |
725 else if (strcmp(encname, "Cp1252") == 0 || |
827 } else if (strcmp(encname, "Cp1252") == 0 || |
726 /* This is a temporary fix until we move */ |
828 /* This is a temporary fix until we move */ |
727 /* to wide character versions of all Windows */ |
829 /* to wide character versions of all Windows */ |
728 /* calls. */ |
830 /* calls. */ |
729 strcmp(encname, "utf-16le") == 0) |
831 strcmp(encname, "utf-16le") == 0) { |
730 fastEncoding = FAST_CP1252; |
832 fastEncoding = FAST_CP1252; |
731 else { |
833 } else { |
732 fastEncoding = NO_FAST_ENCODING; |
834 fastEncoding = NO_FAST_ENCODING; |
733 jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc); |
835 jnuEncoding = (jstring)(*env)->NewGlobalRef(env, enc); |
734 } |
836 } |
735 (*env)->ReleaseStringUTFChars(env, enc, encname); |
837 (*env)->ReleaseStringUTFChars(env, enc, encname); |
736 } |
838 } |
748 String_getBytes_ID = (*env)->GetMethodID(env, strClazz, |
850 String_getBytes_ID = (*env)->GetMethodID(env, strClazz, |
749 "getBytes", "(Ljava/lang/String;)[B"); |
851 "getBytes", "(Ljava/lang/String;)[B"); |
750 CHECK_NULL(String_getBytes_ID); |
852 CHECK_NULL(String_getBytes_ID); |
751 String_init_ID = (*env)->GetMethodID(env, strClazz, |
853 String_init_ID = (*env)->GetMethodID(env, strClazz, |
752 "<init>", "([BLjava/lang/String;)V"); |
854 "<init>", "([BLjava/lang/String;)V"); |
753 } |
855 String_coder_ID = (*env)->GetFieldID(env, strClazz, "coder", "B"); |
754 |
856 String_value_ID = (*env)->GetFieldID(env, strClazz, "value", "[B"); |
755 static jboolean isJNUEncodingSupported = JNI_FALSE; |
857 } |
756 static jboolean jnuEncodingSupported(JNIEnv *env) { |
|
757 jboolean exe; |
|
758 if (isJNUEncodingSupported == JNI_TRUE) { |
|
759 return JNI_TRUE; |
|
760 } |
|
761 isJNUEncodingSupported = (jboolean) JNU_CallStaticMethodByName ( |
|
762 env, &exe, |
|
763 "java/nio/charset/Charset", |
|
764 "isSupported", |
|
765 "(Ljava/lang/String;)Z", |
|
766 jnuEncoding).z; |
|
767 return isJNUEncodingSupported; |
|
768 } |
|
769 |
|
770 |
858 |
771 JNIEXPORT jstring |
859 JNIEXPORT jstring |
772 NewStringPlatform(JNIEnv *env, const char *str) |
860 NewStringPlatform(JNIEnv *env, const char *str) |
773 { |
861 { |
774 return JNU_NewStringPlatform(env, str); |
862 return JNU_NewStringPlatform(env, str); |
775 } |
863 } |
776 |
864 |
777 JNIEXPORT jstring JNICALL |
865 JNIEXPORT jstring JNICALL |
778 JNU_NewStringPlatform(JNIEnv *env, const char *str) |
866 JNU_NewStringPlatform(JNIEnv *env, const char *str) |
779 { |
867 { |
780 jstring result = NULL; |
|
781 jbyteArray hab = 0; |
|
782 int len; |
|
783 |
|
784 if (fastEncoding == NO_ENCODING_YET) { |
868 if (fastEncoding == NO_ENCODING_YET) { |
785 initializeEncoding(env); |
869 initializeEncoding(env); |
786 JNU_CHECK_EXCEPTION_RETURN(env, NULL); |
870 JNU_CHECK_EXCEPTION_RETURN(env, NULL); |
787 } |
871 } |
788 |
872 |
790 return newString8859_1(env, str); |
874 return newString8859_1(env, str); |
791 if (fastEncoding == FAST_646_US) |
875 if (fastEncoding == FAST_646_US) |
792 return newString646_US(env, str); |
876 return newString646_US(env, str); |
793 if (fastEncoding == FAST_CP1252) |
877 if (fastEncoding == FAST_CP1252) |
794 return newStringCp1252(env, str); |
878 return newStringCp1252(env, str); |
795 |
879 if (fastEncoding == FAST_UTF_8) |
796 if ((*env)->EnsureLocalCapacity(env, 2) < 0) |
880 return newStringUTF8(env, str); |
797 return NULL; |
881 return newStringJava(env, str); |
798 |
|
799 len = (int)strlen(str); |
|
800 hab = (*env)->NewByteArray(env, len); |
|
801 if (hab != 0) { |
|
802 jclass strClazz = JNU_ClassString(env); |
|
803 CHECK_NULL_RETURN(strClazz, 0); |
|
804 (*env)->SetByteArrayRegion(env, hab, 0, len, (jbyte *)str); |
|
805 if (jnuEncodingSupported(env)) { |
|
806 result = (*env)->NewObject(env, strClazz, |
|
807 String_init_ID, hab, jnuEncoding); |
|
808 } else { |
|
809 /*If the encoding specified in sun.jnu.encoding is not endorsed |
|
810 by "Charset.isSupported" we have to fall back to use String(byte[]) |
|
811 explicitly here without specifying the encoding name, in which the |
|
812 StringCoding class will pickup the iso-8859-1 as the fallback |
|
813 converter for us. |
|
814 */ |
|
815 jmethodID mid = (*env)->GetMethodID(env, strClazz, |
|
816 "<init>", "([B)V"); |
|
817 if (mid != NULL) { |
|
818 result = (*env)->NewObject(env, strClazz, mid, hab); |
|
819 } |
|
820 } |
|
821 (*env)->DeleteLocalRef(env, hab); |
|
822 return result; |
|
823 } |
|
824 return NULL; |
|
825 } |
882 } |
826 |
883 |
827 JNIEXPORT const char * |
884 JNIEXPORT const char * |
828 GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) |
885 GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) |
829 { |
886 { |
830 return JNU_GetStringPlatformChars(env, jstr, isCopy); |
887 return JNU_GetStringPlatformChars(env, jstr, isCopy); |
831 } |
888 } |
832 |
889 |
833 JNIEXPORT const char * JNICALL |
890 static const char* getStringBytes(JNIEnv *env, jstring jstr) { |
834 JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) |
|
835 { |
|
836 char *result = NULL; |
891 char *result = NULL; |
837 jbyteArray hab = 0; |
892 jbyteArray hab = 0; |
838 |
|
839 if (isCopy) |
|
840 *isCopy = JNI_TRUE; |
|
841 |
|
842 if (fastEncoding == NO_ENCODING_YET) { |
|
843 initializeEncoding(env); |
|
844 JNU_CHECK_EXCEPTION_RETURN(env, 0); |
|
845 } |
|
846 |
|
847 if ((fastEncoding == FAST_8859_1) || (fastEncoding == NO_ENCODING_YET)) |
|
848 return getString8859_1Chars(env, jstr); |
|
849 if (fastEncoding == FAST_646_US) |
|
850 return getString646_USChars(env, jstr); |
|
851 if (fastEncoding == FAST_CP1252) |
|
852 return getStringCp1252Chars(env, jstr); |
|
853 |
893 |
854 if ((*env)->EnsureLocalCapacity(env, 2) < 0) |
894 if ((*env)->EnsureLocalCapacity(env, 2) < 0) |
855 return 0; |
895 return 0; |
856 |
896 |
857 if (jnuEncodingSupported(env)) { |
897 if (jnuEncodingSupported(env)) { |
881 |
921 |
882 (*env)->DeleteLocalRef(env, hab); |
922 (*env)->DeleteLocalRef(env, hab); |
883 return result; |
923 return result; |
884 } |
924 } |
885 |
925 |
|
926 static const char* |
|
927 getStringUTF8(JNIEnv *env, jstring jstr) |
|
928 { |
|
929 int i; |
|
930 char *result; |
|
931 jbyteArray value; |
|
932 jint len; |
|
933 jbyte *str; |
|
934 jint rlen; |
|
935 int ri; |
|
936 jbyte coder = (*env)->GetByteField(env, jstr, String_coder_ID); |
|
937 if (coder != java_lang_String_LATIN1) { |
|
938 return getStringBytes(env, jstr); |
|
939 } |
|
940 if ((*env)->EnsureLocalCapacity(env, 2) < 0) { |
|
941 return NULL; |
|
942 } |
|
943 value = (*env)->GetObjectField(env, jstr, String_value_ID); |
|
944 if (value == NULL) |
|
945 return NULL; |
|
946 len = (*env)->GetArrayLength(env, value); |
|
947 str = (*env)->GetPrimitiveArrayCritical(env, value, NULL); |
|
948 if (str == NULL) { |
|
949 return NULL; |
|
950 } |
|
951 |
|
952 rlen = len; |
|
953 // we need two bytes for each latin-1 char above 127 (negative jbytes) |
|
954 for (i = 0; i < len; i++) { |
|
955 if (str[i] < 0) { |
|
956 rlen++; |
|
957 } |
|
958 } |
|
959 |
|
960 result = MALLOC_MIN4(rlen); |
|
961 if (result == NULL) { |
|
962 (*env)->ReleasePrimitiveArrayCritical(env, value, str, 0); |
|
963 JNU_ThrowOutOfMemoryError(env, 0); |
|
964 return NULL; |
|
965 } |
|
966 |
|
967 for (ri = 0, i = 0; i < len; i++) { |
|
968 jbyte c = str[i]; |
|
969 if (c < 0) { |
|
970 result[ri++] = (char)(0xc0 | ((c & 0xff) >> 6)); |
|
971 result[ri++] = (char)(0x80 | (c & 0x3f)); |
|
972 } else { |
|
973 result[ri++] = c; |
|
974 } |
|
975 } |
|
976 (*env)->ReleasePrimitiveArrayCritical(env, value, str, 0); |
|
977 result[rlen] = '\0'; |
|
978 return result; |
|
979 } |
|
980 |
|
981 JNIEXPORT const char * JNICALL |
|
982 JNU_GetStringPlatformChars(JNIEnv *env, jstring jstr, jboolean *isCopy) |
|
983 { |
|
984 |
|
985 if (isCopy) |
|
986 *isCopy = JNI_TRUE; |
|
987 |
|
988 if (fastEncoding == NO_ENCODING_YET) { |
|
989 initializeEncoding(env); |
|
990 JNU_CHECK_EXCEPTION_RETURN(env, 0); |
|
991 } |
|
992 |
|
993 if ((fastEncoding == FAST_8859_1) || (fastEncoding == NO_ENCODING_YET)) |
|
994 return getString8859_1Chars(env, jstr); |
|
995 if (fastEncoding == FAST_646_US) |
|
996 return getString646_USChars(env, jstr); |
|
997 if (fastEncoding == FAST_CP1252) |
|
998 return getStringCp1252Chars(env, jstr); |
|
999 if (fastEncoding == FAST_UTF_8) |
|
1000 return getStringUTF8(env, jstr); |
|
1001 else |
|
1002 return getStringBytes(env, jstr); |
|
1003 } |
|
1004 |
886 JNIEXPORT void JNICALL |
1005 JNIEXPORT void JNICALL |
887 JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str) |
1006 JNU_ReleaseStringPlatformChars(JNIEnv *env, jstring jstr, const char *str) |
888 { |
1007 { |
889 free((void *)str); |
1008 free((void *)str); |
890 } |
1009 } |