|
1 | 1 | #include "herb_jni.h" |
2 | 2 | #include "extension_helpers.h" |
| 3 | +#include "nodes.h" |
3 | 4 |
|
4 | 5 | #include "../../src/include/extract.h" |
5 | 6 | #include "../../src/include/herb.h" |
| 7 | +#include "../../src/include/diff/herb_diff.h" |
6 | 8 | #include "../../src/include/lib/hb_allocator.h" |
7 | 9 | #include "../../src/include/lib/hb_buffer.h" |
8 | 10 |
|
@@ -246,6 +248,83 @@ Java_org_herb_Herb_parseRuby(JNIEnv* env, jclass clazz, jstring source) { |
246 | 248 | return result; |
247 | 249 | } |
248 | 250 |
|
| 251 | +JNIEXPORT jobject JNICALL |
| 252 | +Java_org_herb_Herb_diff(JNIEnv* env, jclass clazz, jstring old_source, jstring new_source) { |
| 253 | + const char* old_src = (*env)->GetStringUTFChars(env, old_source, 0); |
| 254 | + const char* new_src = (*env)->GetStringUTFChars(env, new_source, 0); |
| 255 | + |
| 256 | + hb_allocator_T old_allocator; |
| 257 | + hb_allocator_T new_allocator; |
| 258 | + hb_allocator_T diff_allocator; |
| 259 | + |
| 260 | + if (!hb_allocator_init(&old_allocator, HB_ALLOCATOR_ARENA) |
| 261 | + || !hb_allocator_init(&new_allocator, HB_ALLOCATOR_ARENA) |
| 262 | + || !hb_allocator_init(&diff_allocator, HB_ALLOCATOR_ARENA)) { |
| 263 | + (*env)->ReleaseStringUTFChars(env, old_source, old_src); |
| 264 | + (*env)->ReleaseStringUTFChars(env, new_source, new_src); |
| 265 | + return NULL; |
| 266 | + } |
| 267 | + |
| 268 | + parser_options_T parser_options = HERB_DEFAULT_PARSER_OPTIONS; |
| 269 | + |
| 270 | + AST_DOCUMENT_NODE_T* old_root = herb_parse(old_src, &parser_options, &old_allocator); |
| 271 | + AST_DOCUMENT_NODE_T* new_root = herb_parse(new_src, &parser_options, &new_allocator); |
| 272 | + herb_diff_result_T* diff_result = herb_diff(old_root, new_root, &diff_allocator); |
| 273 | + |
| 274 | + jclass diff_result_class = (*env)->FindClass(env, "org/herb/DiffResult"); |
| 275 | + jclass diff_operation_class = (*env)->FindClass(env, "org/herb/DiffOperation"); |
| 276 | + jclass array_list_class = (*env)->FindClass(env, "java/util/ArrayList"); |
| 277 | + |
| 278 | + jmethodID diff_result_constructor = (*env)->GetMethodID(env, diff_result_class, "<init>", "(ZLjava/util/List;)V"); |
| 279 | + jmethodID diff_operation_constructor = (*env)->GetMethodID(env, diff_operation_class, "<init>", "(Ljava/lang/String;[ILjava/lang/Object;Ljava/lang/Object;II)V"); |
| 280 | + jmethodID array_list_constructor = (*env)->GetMethodID(env, array_list_class, "<init>", "()V"); |
| 281 | + jmethodID array_list_add = (*env)->GetMethodID(env, array_list_class, "add", "(Ljava/lang/Object;)Z"); |
| 282 | + |
| 283 | + jobject operations_list = (*env)->NewObject(env, array_list_class, array_list_constructor); |
| 284 | + |
| 285 | + size_t operation_count = herb_diff_operation_count(diff_result); |
| 286 | + |
| 287 | + for (size_t index = 0; index < operation_count; index++) { |
| 288 | + const herb_diff_operation_T* operation = herb_diff_operation_at(diff_result, index); |
| 289 | + |
| 290 | + jstring type_string = (*env)->NewStringUTF(env, herb_diff_operation_type_to_string(operation->type)); |
| 291 | + jintArray path_array = (*env)->NewIntArray(env, operation->path.depth); |
| 292 | + jint* path_elements = (*env)->GetIntArrayElements(env, path_array, NULL); |
| 293 | + |
| 294 | + for (uint16_t path_index = 0; path_index < operation->path.depth; path_index++) { |
| 295 | + path_elements[path_index] = (jint) operation->path.indices[path_index]; |
| 296 | + } |
| 297 | + |
| 298 | + (*env)->ReleaseIntArrayElements(env, path_array, path_elements, 0); |
| 299 | + |
| 300 | + jobject old_node = operation->old_node != NULL ? CreateASTNode(env, (AST_NODE_T*) operation->old_node) : NULL; |
| 301 | + jobject new_node = operation->new_node != NULL ? CreateASTNode(env, (AST_NODE_T*) operation->new_node) : NULL; |
| 302 | + |
| 303 | + jobject diff_operation = (*env)->NewObject( |
| 304 | + env, diff_operation_class, diff_operation_constructor, |
| 305 | + type_string, path_array, old_node, new_node, |
| 306 | + (jint) operation->old_index, (jint) operation->new_index |
| 307 | + ); |
| 308 | + |
| 309 | + (*env)->CallBooleanMethod(env, operations_list, array_list_add, diff_operation); |
| 310 | + } |
| 311 | + |
| 312 | + jboolean identical = herb_diff_trees_identical(diff_result) ? JNI_TRUE : JNI_FALSE; |
| 313 | + jobject result = (*env)->NewObject(env, diff_result_class, diff_result_constructor, identical, operations_list); |
| 314 | + |
| 315 | + ast_node_free((AST_NODE_T*) old_root, &old_allocator); |
| 316 | + ast_node_free((AST_NODE_T*) new_root, &new_allocator); |
| 317 | + |
| 318 | + hb_allocator_destroy(&diff_allocator); |
| 319 | + hb_allocator_destroy(&old_allocator); |
| 320 | + hb_allocator_destroy(&new_allocator); |
| 321 | + |
| 322 | + (*env)->ReleaseStringUTFChars(env, old_source, old_src); |
| 323 | + (*env)->ReleaseStringUTFChars(env, new_source, new_src); |
| 324 | + |
| 325 | + return result; |
| 326 | +} |
| 327 | + |
249 | 328 | JNIEXPORT jstring JNICALL |
250 | 329 | Java_org_herb_Herb_extractHTML(JNIEnv* env, jclass clazz, jstring source) { |
251 | 330 | const char* src = (*env)->GetStringUTFChars(env, source, 0); |
|
0 commit comments