source: main/trunk/greenstone2/common-src/indexers/mgpp/jni/MGPPSearchWrapperImpl.cpp@ 37352

Last change on this file since 37352 was 37352, checked in by davidb, 14 months ago

STL string and c_str() combination recoded due to compiler error from MacOS gcc/clang. See comment in code for more details

File size: 19.1 KB
Line 
1/*
2 * MGPPSearchWrapperImpl.cpp
3 * Copyright (C) 2007 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19#ifdef __WIN32__
20#include <win32cfg.h>
21#include <strstream>
22#include <sstream>
23#else
24#ifdef __APPLE__
25#include <strstream>
26#include <sstream>
27#else
28#include <sstream>
29#endif
30#endif
31
32#include <jni.h>
33
34#ifdef __MINGW32__
35
36/* Cross compiling for Windows
37 Want the type definitions in *win32* version of jni_md.h but
38 this then leads to C-mangled style functions which we *don't*
39 want. The following achieves this */
40
41#undef JNIEXPORT
42#undef JNIIMPORT
43#undef JNICALL
44
45#define JNIEXPORT
46#define JNIIMPORT
47#define JNICALL
48#endif
49
50#include "org_greenstone_mgpp_MGPPSearchWrapper.h"
51#include "MGPPSearchWrapperImpl.h"
52#include "GSDLQueryParser.h"
53#include "MGQuery.h"
54
55// toggle debugging
56//#define _DEBUG
57
58MGPPSearchData::MGPPSearchData() {
59 indexData = new IndexData();
60 queryInfo = new QueryInfo();
61
62 if (queryInfo==NULL) {
63 cerr<<"couldn't allocate new query info\n";
64 if (indexData!=NULL) {
65 delete indexData;
66 }
67 }
68
69 resetDefaults();
70}
71
72MGPPSearchData::~MGPPSearchData() {
73 if (indexData !=NULL) {
74 delete indexData;
75 }
76 if (queryInfo !=NULL) {
77 delete queryInfo;
78 }
79}
80
81void MGPPSearchData::resetDefaults() {
82 // set all the default params
83 SetCStr(queryInfo->docLevel, "Document"); // the level to search at
84 queryInfo->maxDocs = 50;
85 queryInfo->sortByRank = true;
86 queryInfo->exactWeights = false;
87 queryInfo->needRankInfo = true;
88 queryInfo->needTermFreqs = true;
89
90 UCArrayClear(level);
91 SetCStr(level, "Document"); // the level to return docs at
92 defaultStemMethod=0;
93 defaultBoolCombine=0;
94 maxNumeric = 4;
95
96}
97
98// ********************************************
99// initialisation stuff
100// ********************************************
101
102// cached ids for java stuff
103jfieldID FID_mgpp_data = NULL; // MGPPSearchData
104jfieldID FID_query_result = NULL; // MGPPQueryResult
105jmethodID MID_addDoc=NULL; // MGPPQueryResult.addDoc()
106jmethodID MID_addTerm=NULL; // MGPPQueryResult.addTerm()
107jmethodID MID_setTotalDocs=NULL; // MGPPQueryResult.setTotalDocs()
108jmethodID MID_clearResult=NULL; //MGPPQueryResult.clear()
109jmethodID MID_setSyntaxError=NULL; // MGPPQueryResult.setSyntaxError()
110jclass CID_String=NULL; // class ID of String
111
112/* to access objects and methods on java side, need their field/method ids -
113 this initialises them at the start to avoid recalculating them each time they
114 are needed
115Note: the descriptors need to be exactly right, otherwise you get an error
116saying "no such field" but no reference to the fact that it has the right
117name but the wrong type.
118Note: apparently the jclass is a local ref and should only work
119in the method that created it. It seems to work ok, but I'll make it
120 global cos the book said I should, and it may avoid future hassles.
121*/
122JNIEXPORT void JNICALL
123Java_org_greenstone_mgpp_MGPPSearchWrapper_initIDs (JNIEnv *j_env, jclass j_cls) {
124
125 FID_mgpp_data = j_env->GetFieldID(j_cls, "mgpp_data_ptr_", "J"); //a long-"J"
126 if (FID_mgpp_data==NULL) {
127 cerr <<"MGPP JNI: field mgpp_data_ptr_ not found"<<endl;
128 }
129
130 FID_query_result = j_env->GetFieldID(j_cls, "mgpp_query_result_", "Lorg/greenstone/mgpp/MGPPQueryResult;"); // an object -"L<class name>;"
131 if (FID_query_result==NULL) {
132 cerr <<"MGPP JNI: field mgpp_query_result_ not found"<<endl;
133 }
134 // the methods we want to use
135
136 // addDoc(long doc, float rank)
137 jclass JC_MGPPQueryResult = j_env->FindClass("org/greenstone/mgpp/MGPPQueryResult");
138 MID_addDoc = j_env->GetMethodID(JC_MGPPQueryResult, "addDoc", "(JF)V");
139 if (MID_addDoc==NULL) {
140 cerr <<"MGPP JNI: addDoc method not found"<<endl;
141 }
142 // addTerm(String term, String tag, int stem_method, long match_docs,
143 // long term_freq, String[] equiv_terms)
144 MID_addTerm = j_env->GetMethodID(JC_MGPPQueryResult, "addTerm", "(Ljava/lang/String;Ljava/lang/String;IJJ[Ljava/lang/String;)V");
145 if (MID_addTerm==NULL) {
146 cerr <<"MGPP JNI: method addTerm not found"<<endl;
147 }
148
149 // setTotalDocs(long)
150 MID_setTotalDocs = j_env->GetMethodID(JC_MGPPQueryResult, "setTotalDocs", "(J)V");
151 if (MID_setTotalDocs==NULL) {
152 cerr <<"MGPP JNI: method setTotalDocs not found"<<endl;
153 }
154
155 MID_clearResult = j_env->GetMethodID(JC_MGPPQueryResult, "clear", "()V");
156 if (MID_clearResult==NULL) {
157 cerr <<"MGPP JNI: method clear not found"<<endl;
158 }
159 MID_setSyntaxError = j_env->GetMethodID(JC_MGPPQueryResult, "setSyntaxError", "(Z)V");
160 if (MID_clearResult==NULL) {
161 cerr <<"MGPP JNI: method setSyntaxError not found"<<endl;
162 }
163
164 // get the class for String to use in NewObjectArray in runQuery()
165 // FindClass returns a local reference - have to convert it to a global one
166 jclass local_CID_String = j_env->FindClass("java/lang/String");
167 if (local_CID_String==NULL) {
168 cerr <<"MGPP JNI: java String class not found"<<endl;
169 } else {
170 /* create a global ref */
171 CID_String = (jclass)j_env->NewGlobalRef(local_CID_String);
172 /* The local reference is no longer useful */
173 j_env->DeleteLocalRef(local_CID_String);
174
175 /* Is the global reference created successfully? */
176 if (CID_String == NULL) {
177 return; /* out of memory exception thrown */
178 }
179 }
180
181}
182
183/* the java side MGPPSearchWrapper has a pointer to a C++ object - MGPPSearchData
184 initialise this and set the pointer
185*/
186JNIEXPORT jboolean JNICALL
187Java_org_greenstone_mgpp_MGPPSearchWrapper_initCppSide (JNIEnv *j_env, jobject j_obj){
188
189#ifdef _DEBUG
190 cerr << "**** JNI debugging for GS3. initCppSide: SetLongField()\n";
191#endif
192
193 MGPPSearchData * data = new MGPPSearchData();
194
195#ifdef _DEBUG
196 fprintf (stderr, "1a. data before SetLongField() is: %ld and as hex: %lX\n", data, data);
197 fprintf (stderr, "1b. FID_mgpp_data before SetLongField() is: %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
198#endif
199
200 j_env->SetLongField(j_obj, FID_mgpp_data, (jlong)data);
201
202#ifdef _DEBUG
203 fprintf (stderr, "1a. data after SetLongField() is: %ld and as hex: %lX\n", data, data);
204 fprintf (stderr, "1b. FID_mgpp_data after SetLongField() is: %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
205#endif
206
207 return true;
208
209}
210
211//******************************************
212// do a query
213// ****************************************
214
215/* load the IndexData - cached for querying
216 */
217JNIEXPORT jboolean JNICALL
218Java_org_greenstone_mgpp_MGPPSearchWrapper_loadIndexData (JNIEnv *j_env, jobject j_obj, jstring j_index_name) {
219#ifdef _DEBUG
220 fprintf (stderr, "in loadIndexData\n");
221#endif
222
223 jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
224
225#ifdef _DEBUG
226 fprintf (stderr, "1. data_ptr at start is: %ld and as hex: %lX\n", data_ptr, data_ptr);
227#endif
228
229 MGPPSearchData * data = (MGPPSearchData *)data_ptr;
230
231#ifdef __WIN32__
232 const char* base_dir = "";
233#else
234 const char* base_dir = "/";
235#endif
236
237 const char * index_name = j_env->GetStringUTFChars( j_index_name, NULL);
238 if (index_name==NULL) {
239 return false;
240 }
241
242 jboolean j_result=false;
243
244 // why doesn't this complain about const??
245 if (data->indexData->LoadData(base_dir, index_name)) {
246 j_result=true;
247 }
248
249 // release any gets
250 j_env->ReleaseStringUTFChars(j_index_name, index_name);
251
252 return j_result;
253}
254
255/* unload the data
256 */
257JNIEXPORT jboolean JNICALL
258Java_org_greenstone_mgpp_MGPPSearchWrapper_unloadIndexData (JNIEnv *j_env, jobject j_obj) {
259
260#ifdef _DEBUG
261 fprintf (stderr, "in unloadIndexData\n");
262#endif
263
264 jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
265
266#ifdef _DEBUG
267 fprintf (stderr, "1. data_ptr at start is: %ld and as hex: %lX\n", data_ptr, data_ptr);
268#endif
269
270 MGPPSearchData * data = (MGPPSearchData *)data_ptr;
271
272 data->indexData->UnloadData();
273 return true;
274
275}
276
277/* reset the stored settings
278*/
279JNIEXPORT void JNICALL
280Java_org_greenstone_mgpp_MGPPSearchWrapper_reset (JNIEnv *j_env, jobject j_obj) {
281
282 jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
283 MGPPSearchData * data = (MGPPSearchData *)data_ptr;
284 data->resetDefaults();
285
286
287}
288/* do the actual query - the results are written to query_result held on the
289 java side */
290JNIEXPORT void JNICALL
291Java_org_greenstone_mgpp_MGPPSearchWrapper_runQuery (JNIEnv *j_env, jobject j_obj, jstring j_query){
292
293 jthrowable exc; // an exception - check if something funny has happened
294 const char *query = j_env->GetStringUTFChars(j_query, NULL);
295 if (query==NULL) {
296 return; // exception already thrown
297 }
298 // turn to UCArray for mgpp and then release the string
299 UCArray queryArray;
300 SetCStr(queryArray, query);
301 j_env->ReleaseStringUTFChars(j_query, query);
302
303 // the query data
304 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
305
306 // the result to write to
307 jobject result_ptr = j_env->GetObjectField(j_obj, FID_query_result);
308 if (result_ptr==NULL) {
309 cerr <<"couldn't access the result to write to"<<endl;
310 return;
311 }
312
313 // clear the result
314 j_env->CallVoidMethod(result_ptr, MID_clearResult);
315 exc = j_env->ExceptionOccurred(); // this catches the exception I think - it
316 //wont be thrown any further
317 if (exc) {
318 j_env->ExceptionDescribe();
319 return;
320 }
321 // the mgpp QueryResult that we will use
322 ExtQueryResult queryResult;
323
324 QueryNode * queryTree = NULL;
325 // parse the query string into a tree structure
326 queryTree = ParseQuery(queryArray, data->defaultBoolCombine,
327 data->defaultStemMethod, data->maxNumeric);
328 if (queryTree == NULL) {
329 // invalid syntax
330 j_env->CallVoidMethod(result_ptr, MID_setSyntaxError, true);
331 cerr << "MGPPSearchWrapperImpl: invalid query syntax!!\n";
332 return;
333 }
334 // print the query
335 PrintNode (cout, queryTree);
336 // finally, do the query
337 MGQuery(*(data->indexData), *(data->queryInfo), queryTree, queryResult, data->level);
338
339 delete queryTree;
340
341 // convert queryResult to the java side version
342 // use levels rather than docs of ExtQueryResult
343 // CallVoidMethod(obj, method id, args to method)
344 for (int i=0; i<queryResult.levels.size(); i++) {
345 jlong doc = queryResult.levels[i];
346 jfloat rank = queryResult.ranks[i];
347 j_env->CallVoidMethod(result_ptr, MID_addDoc, doc, rank);
348 exc = j_env->ExceptionOccurred();
349 if (exc) {
350 j_env->ExceptionDescribe();
351 return;
352 }
353
354 }
355
356 // actual num of docs
357 jlong total = queryResult.actualNumDocs;
358 j_env->CallVoidMethod(result_ptr, MID_setTotalDocs, total);
359 exc = j_env->ExceptionOccurred();
360 if (exc) {
361 j_env->ExceptionDescribe();
362 return;
363 }
364
365 // the terms
366 for (int j=0; j<queryResult.termFreqs.size(); j++) {
367
368 TermFreqData tf = queryResult.termFreqs[j];
369 jstring term = j_env->NewStringUTF(GetCStr(tf.term));
370 jstring tag = j_env->NewStringUTF(GetCStr(tf.tag));
371 jint stem = tf.stemMethod;
372 jlong match = tf.matchDocs;
373 jlong freq = tf.termFreq;
374
375 jobjectArray equivs=NULL;
376 jstring empty = j_env->NewStringUTF(""); // the initial object to fill the array
377 jint num_equivs = tf.equivTerms.size();
378 equivs = j_env->NewObjectArray(num_equivs, CID_String, empty);
379 if (equivs==NULL) {
380 cerr<<"couldn't create object array"<<endl;
381
382 } else {
383 for (int k=0; k<num_equivs;k++) {
384 jstring equiv = j_env->NewStringUTF(GetCStr(tf.equivTerms[k]));
385 j_env->SetObjectArrayElement(equivs, k, equiv);
386 }
387
388
389 j_env->CallVoidMethod(result_ptr, MID_addTerm, term, tag, stem, match, freq, equivs);
390 exc = j_env->ExceptionOccurred();
391 if (exc) {
392 j_env->ExceptionDescribe();
393 return;
394 }
395 }
396 }
397
398
399}
400
401JNIEXPORT void JNICALL
402Java_org_greenstone_mgpp_MGPPSearchWrapper_setStem (JNIEnv *j_env,
403 jobject j_obj,
404 jboolean j_on) {
405 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
406 if (j_on) {
407 data->defaultStemMethod |= 2;
408 } else {
409 data->defaultStemMethod &= 0xd;
410 }
411
412}
413
414JNIEXPORT void JNICALL
415Java_org_greenstone_mgpp_MGPPSearchWrapper_setAccentFold (JNIEnv *j_env,
416 jobject j_obj,
417 jboolean j_on) {
418 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
419 if (j_on) {
420 data->defaultStemMethod |= 4;
421 } else {
422 data->defaultStemMethod &= 0xb;
423 }
424}
425
426
427JNIEXPORT void JNICALL
428Java_org_greenstone_mgpp_MGPPSearchWrapper_setCase (JNIEnv *j_env,
429 jobject j_obj,
430 jboolean j_on) {
431 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
432
433 if (j_on) {
434 data->defaultStemMethod |= 1;
435 } else {
436 data->defaultStemMethod &= 0xe;
437 }
438}
439
440JNIEXPORT void JNICALL
441Java_org_greenstone_mgpp_MGPPSearchWrapper_setMaxDocs (JNIEnv *j_env,
442 jobject j_obj,
443 jint j_max) {
444 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
445 data->queryInfo->maxDocs=j_max;
446}
447
448JNIEXPORT void JNICALL
449Java_org_greenstone_mgpp_MGPPSearchWrapper_setMaxNumeric (JNIEnv *j_env,
450 jobject j_obj,
451 jint j_max) {
452 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
453 data->maxNumeric=j_max;
454}
455
456JNIEXPORT void JNICALL
457Java_org_greenstone_mgpp_MGPPSearchWrapper_setSortByRank (JNIEnv *j_env,
458 jobject j_obj,
459 jboolean j_on) {
460 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
461
462 data->queryInfo->sortByRank=j_on;
463}
464
465JNIEXPORT void JNICALL
466Java_org_greenstone_mgpp_MGPPSearchWrapper_setReturnTerms(JNIEnv *j_env,
467 jobject j_obj,
468 jboolean j_on) {
469 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
470 data->queryInfo->needTermFreqs = j_on;
471
472}
473
474JNIEXPORT void JNICALL
475Java_org_greenstone_mgpp_MGPPSearchWrapper_setQueryLevel(JNIEnv *j_env,
476 jobject j_obj,
477 jstring j_level){
478
479 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
480
481 const char * level = j_env->GetStringUTFChars(j_level, NULL);
482 if (level==NULL) {
483 return; // exception already thrown
484 }
485
486 data->queryInfo->docLevel.clear();
487 SetCStr(data->queryInfo->docLevel, level);
488
489 // release the java stuff
490 j_env->ReleaseStringUTFChars(j_level, level);
491
492}
493
494JNIEXPORT void JNICALL
495Java_org_greenstone_mgpp_MGPPSearchWrapper_setReturnLevel(JNIEnv *j_env,
496 jobject j_obj,
497 jstring j_level){
498 // print to stderr start of setReturnLevel, print out FID..
499 // %ld or %x -> need to print out pointer -
500 // Later consider field containing unsignedlong instead of long
501
502#ifdef _DEBUG
503 cerr << "In MGPPSearchWrapperImpl.setReturnLevel()\n";
504 fprintf (stderr, "1. FID_mgpp_data at start is: %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
505#endif
506
507 jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
508
509#ifdef _DEBUG
510 fprintf (stderr, "1a. data_ptr at start is: %ld and as hex: %lX\n", data_ptr, data_ptr);
511#endif
512
513 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
514
515#ifdef _DEBUG
516 fprintf (stderr, "2a. FID_mgpp_data after data instantiation: %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
517 fprintf (stderr, "2b. Pointer value of data upon inst: %ld and as hex: %lX\n", data, data);
518#endif
519
520 // print out FID again.. as long decimal and as hex
521 // %ld or %x -> need to print out pointer -
522 // in the C code in the Setlong bit in this file
523 // And the place on the java side, maybe in the configure
524 // org.greenstone.gsdl3.service.GS2MGPPSearch.configure(Lorg/w3c/dom/Element;Lorg/w3c/dom/Element;)Z+18
525 // find out what value we're SETTING the value of the pointer to
526 const char * level = j_env->GetStringUTFChars(j_level, NULL);
527 if (level==NULL) {
528 return; // exception already thrown
529 }
530
531#ifdef _DEBUG
532 fprintf (stderr, "3a. FID_mgpp_data after level: %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
533 fprintf (stderr, "3b. Pointer value of data after level: %ld and as hex: %lX\n", data, data);
534#endif
535
536 data->level.clear();
537
538#ifdef _DEBUG
539 fprintf (stderr, "4a. FID_mgpp_data after data->level.clear(): %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
540 fprintf (stderr, "4b. Pointer value of data after level.clear(): %ld and as hex: %lX\n", data, data);
541#endif
542
543 SetCStr(data->level, level);
544
545#ifdef _DEBUG
546 fprintf (stderr, "5a. FID_mgpp_data after SetCStr on data: %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
547 fprintf (stderr, "5b. Pointer value of data after SetCStr: %ld and as hex: %lX\n", data, data);
548#endif
549
550 // release the java stuff
551 j_env->ReleaseStringUTFChars(j_level, level);
552
553#ifdef _DEBUG
554 fprintf (stderr, "5a. FID_mgpp_data at end of setReturnLevel: %ld and as hex: %lX\n", FID_mgpp_data, FID_mgpp_data);
555 fprintf (stderr, "5b. Pointer value of data at end of SetReturnLevel: %ld and as hex: %lX\n", data, data);
556#endif
557
558}
559
560JNIEXPORT void JNICALL
561Java_org_greenstone_mgpp_MGPPSearchWrapper_setMatchMode (JNIEnv *j_env,
562 jobject j_obj,
563 jint j_mode){
564
565 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
566 data->defaultBoolCombine=j_mode;
567
568}
569
570JNIEXPORT jstring JNICALL
571Java_org_greenstone_mgpp_MGPPSearchWrapper_getQueryParams (JNIEnv *j_env,
572 jobject j_obj){
573
574 MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
575
576 // print the data to a stringstream, then convert to char*, then to
577 //jstring
578
579 stringstream output;
580 output << "Query params:"<<endl
581 // need to change this to use platform specific separator for niceness
582 << "index\t\t"<<data->indexData->basePath<<"/"<<data->indexData->filename<<endl
583 <<"search level\t"<<GetCStr(data->queryInfo->docLevel)<<endl
584 <<"result level\t"<<GetCStr(data->level)<<endl
585 <<"casefold\t"<<(data->defaultStemMethod&1)<<endl
586 <<"stem\t\t"<<(data->defaultStemMethod&2)<<endl
587 <<"order by rank\t"<<data->queryInfo->sortByRank<<endl
588 <<"query type\t"<<(data->defaultBoolCombine==1?"all":"some")<<endl
589 <<"max docs\t"<<data->queryInfo->maxDocs<<endl<<ends;
590
591 // The following 'one-liner' is determiend by MacOS gcc/clang to be fundamentally
592 // not safe. This is because it will return a pointer to the cstr inside the string
593 // returned as output.str(), but that string will be destroyed at the end of the method
594 // meaning the 'cstr' is a dangling pointer
595 //
596 // In actual fact, the way we then take a copy of the cstr and put it into j_result
597 // on this occassion means the dangling pointer isn't subsequently used
598 //
599 // However, let's recode to keep everything above board!
600
601 //const char *result = output.str().c_str();
602
603 const string result_str = output.str();
604 char* result_cstr = new char [result_str.length()+1];
605 strcpy (result_cstr, result_str.c_str());
606
607 jstring j_result = j_env->NewStringUTF(result_cstr);
608 delete (char *)result_cstr;
609 return j_result;
610}
Note: See TracBrowser for help on using the repository browser.