/** * Returns an interned string for the given UTF-8 string. * * @param s null-terminated string to intern * @returns interned Java string equivelent of s or NULL if s is null */ static jstring internString(JNIEnv* env, ParsingContext* parsingContext, const char* s) { if (s == NULL) return NULL; int hash = hashString(s); int bucketIndex = hash & (BUCKET_COUNT - 1); InternedString*** buckets = parsingContext->internedStrings; InternedString** bucket = buckets[bucketIndex]; InternedString* internedString; if (bucket) { // We have a bucket already. Look for the given string. jstring found = findInternedString(bucket, s, hash); if (found) { // We found it! return found; } // We didn't find it. :( // Create a new entry. internedString = newInternedString(env, s, hash); if (internedString == NULL) return NULL; // Expand the bucket. bucket = expandInternedStringBucket(bucket, internedString); if (bucket == NULL) { delete internedString; jniThrowOutOfMemoryError(env, NULL); return NULL; } buckets[bucketIndex] = bucket; return internedString->interned; } else { // We don't even have a bucket yet. Create an entry. internedString = newInternedString(env, s, hash); if (internedString == NULL) return NULL; // Create a new bucket with one entry. bucket = newInternedStringBucket(internedString); if (bucket == NULL) { delete internedString; jniThrowOutOfMemoryError(env, NULL); return NULL; } buckets[bucketIndex] = bucket; return internedString->interned; } }
/** * Creates a new Expat parser. Called from the Java ExpatParser constructor. * * @param object the Java ExpatParser instance * @param javaEncoding the character encoding name * @param processNamespaces true if the parser should handle namespaces * @returns the pointer to the C Expat parser */ static jlong ExpatParser_initialize(JNIEnv* env, jobject object, jstring javaEncoding, jboolean processNamespaces) { // Allocate parsing context. UniquePtr<ParsingContext> context(new ParsingContext(object)); if (context.get() == NULL) { jniThrowOutOfMemoryError(env, NULL); return 0; } context->processNamespaces = processNamespaces; // Create a parser. XML_Parser parser; ScopedUtfChars encoding(env, javaEncoding); if (encoding.c_str() == NULL) { return 0; } if (processNamespaces) { // Use '|' to separate URIs from local names. parser = XML_ParserCreateNS(encoding.c_str(), '|'); } else { parser = XML_ParserCreate(encoding.c_str()); } if (parser != NULL) { if (processNamespaces) { XML_SetNamespaceDeclHandler(parser, startNamespace, endNamespace); XML_SetReturnNSTriplet(parser, 1); } XML_SetCdataSectionHandler(parser, startCdata, endCdata); XML_SetCharacterDataHandler(parser, text); XML_SetCommentHandler(parser, comment); XML_SetDoctypeDeclHandler(parser, startDtd, endDtd); XML_SetElementHandler(parser, startElement, endElement); XML_SetExternalEntityRefHandler(parser, handleExternalEntity); XML_SetNotationDeclHandler(parser, notationDecl); XML_SetProcessingInstructionHandler(parser, processingInstruction); XML_SetUnparsedEntityDeclHandler(parser, unparsedEntityDecl); XML_SetUserData(parser, context.release()); } else { jniThrowOutOfMemoryError(env, NULL); return 0; } return fromXMLParser(parser); }
/** * Creates a new interned string wrapper. Looks up the interned string * representing the given UTF-8 bytes. * * @param bytes null-terminated string to intern * @param hash of bytes * @returns wrapper of interned Java string */ static InternedString* newInternedString(JNIEnv* env, const char* bytes, int hash) { // Allocate a new wrapper. UniquePtr<InternedString> wrapper(new InternedString); if (wrapper.get() == NULL) { jniThrowOutOfMemoryError(env, NULL); return NULL; } // Create a copy of the UTF-8 bytes. // TODO: sometimes we already know the length. Reuse it if so. char* copy = new char[strlen(bytes) + 1]; if (copy == NULL) { jniThrowOutOfMemoryError(env, NULL); return NULL; } strcpy(copy, bytes); wrapper->bytes = copy; // Save the hash. wrapper->hash = hash; // To intern a string, we must first create a new string and then call // intern() on it. We then keep a global reference to the interned string. ScopedLocalRef<jstring> newString(env, env->NewStringUTF(bytes)); if (env->ExceptionCheck()) { return NULL; } // Call intern(). ScopedLocalRef<jstring> interned(env, reinterpret_cast<jstring>(env->CallObjectMethod(newString.get(), internMethod))); if (env->ExceptionCheck()) { return NULL; } // Create a global reference to the interned string. wrapper->interned = reinterpret_cast<jstring>(env->NewGlobalRef(interned.get())); if (env->ExceptionCheck()) { return NULL; } return wrapper.release(); }
/** * Creates a new entity parser. * * @param object the Java ExpatParser instance * @param parentParser pointer * @param javaEncoding the character encoding name * @param javaContext that was provided to handleExternalEntity * @returns the pointer to the C Expat entity parser */ static jlong ExpatParser_createEntityParser(JNIEnv* env, jobject, jlong parentParser, jstring javaContext) { ScopedUtfChars context(env, javaContext); if (context.c_str() == NULL) { return 0; } XML_Parser parent = toXMLParser(parentParser); XML_Parser entityParser = XML_ExternalEntityParserCreate(parent, context.c_str(), NULL); if (entityParser == NULL) { jniThrowOutOfMemoryError(env, NULL); } return fromXMLParser(entityParser); }
void push(JNIEnv* env, jstring s) { if (size == capacity) { int newCapacity = capacity * 2; jstring* newArray = new jstring[newCapacity]; if (newArray == NULL) { jniThrowOutOfMemoryError(env, NULL); return; } memcpy(newArray, array, capacity * sizeof(jstring)); delete[] array; array = newArray; capacity = newCapacity; } array[size++] = s; }
static bool throwExceptionIfNecessary(JNIEnv* env) { long error = ERR_get_error(); if (error == 0) { return false; } char message[256]; ERR_error_string_n(error, message, sizeof(message)); int reason = ERR_GET_REASON(error); if (reason == BN_R_DIV_BY_ZERO) { jniThrowException(env, "java/lang/ArithmeticException", "BigInteger division by zero"); } else if (reason == BN_R_NO_INVERSE) { jniThrowException(env, "java/lang/ArithmeticException", "BigInteger not invertible"); } else if (reason == ERR_R_MALLOC_FAILURE) { jniThrowOutOfMemoryError(env, message); } else { jniThrowException(env, "java/lang/ArithmeticException", message); } return true; }
extern "C" jlong Java_java_util_zip_Inflater_createStream(JNIEnv* env, jobject, jboolean noHeader) { UniquePtr<NativeZipStream> jstream(new NativeZipStream); if (jstream.get() == NULL) { jniThrowOutOfMemoryError(env, NULL); return -1; } jstream->stream.adler = 1; /* * See zlib.h for documentation of the inflateInit2 windowBits parameter. * * zconf.h says the "requirements for inflate are (in bytes) 1 << windowBits * that is, 32K for windowBits=15 (default value) plus a few kilobytes * for small objects." This means that we can happily use the default * here without worrying about memory consumption. */ int err = inflateInit2(&jstream->stream, noHeader ? -DEF_WBITS : DEF_WBITS); if (err != Z_OK) { throwExceptionForZlibError(env, "java/lang/IllegalArgumentException", err, jstream.get()); return -1; } return reinterpret_cast<uintptr_t>(jstream.release()); }
/** * Clones an array of strings. Uses one contiguous block of memory so as to * maximize performance. * * @param address char** to clone * @param count number of attributes */ static jlong ExpatParser_cloneAttributes(JNIEnv* env, jobject, jlong address, jint count) { const char** source = reinterpret_cast<const char**>(static_cast<uintptr_t>(address)); count *= 2; // Figure out how big the buffer needs to be. int arraySize = (count + 1) * sizeof(char*); int totalSize = arraySize; int stringLengths[count]; for (int i = 0; i < count; i++) { int length = strlen(source[i]); stringLengths[i] = length; totalSize += length + 1; } char* buffer = new char[totalSize]; if (buffer == NULL) { jniThrowOutOfMemoryError(env, NULL); return 0; } // Array is at the beginning of the buffer. char** clonedArray = reinterpret_cast<char**>(buffer); clonedArray[count] = NULL; // null terminate // String data follows immediately after. char* destinationString = buffer + arraySize; for (int i = 0; i < count; i++) { const char* sourceString = source[i]; int stringLength = stringLengths[i]; memcpy(destinationString, sourceString, stringLength + 1); clonedArray[i] = destinationString; destinationString += stringLength + 1; } return reinterpret_cast<uintptr_t>(buffer); }