1 // CoolReader3 Engine JNI interface
2 // BASED on Android NDK Plasma example
3
4 #include <jni.h>
5 #include <time.h>
6 #include <android/log.h>
7 #include <android/api-level.h>
8
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13
14 #include "org_coolreader_crengine_Engine.h"
15 #include "org_coolreader_crengine_DocView.h"
16
17 #include "cr3java.h"
18 #include "../../crengine/include/cr3version.h"
19 #include "docview.h"
20 #include "../../crengine/include/crengine.h"
21 #include "../../crengine/include/epubfmt.h"
22 #include "../../crengine/include/pdbfmt.h"
23 #include "../../crengine/include/lvopc.h"
24 #include "../../crengine/include/fb3fmt.h"
25 #include "../../crengine/include/docxfmt.h"
26 #include "../../crengine/include/odtfmt.h"
27 #include "../../crengine/include/lvstream.h"
28
29
30 #include <../../crengine/include/fb2def.h>
31
32 #include "fc-lang-cat.h"
33
34 #define XS_IMPLEMENT_SCHEME 1
35 #include <../../crengine/include/fb2def.h>
36 #include <sys/stat.h>
37
38 #if defined(__arm__) || defined(__aarch64__) || defined(__i386__) || defined(__mips__)
39 #define USE_COFFEECATCH 1
40 #endif
41
42
43 #if USE_COFFEECATCH == 1
44 #include "coffeecatch/coffeecatch.h"
45 #include "coffeecatch/coffeejni.h"
46 #else
47 #define COFFEE_TRY_JNI(ENV, CODE) CODE;
48 #endif
49
50 #ifdef _DEBUG
51 // missing in system ZLIB with DEBUG option turned off
52 int z_verbose=0;
53 extern "C" void z_error(char * msg);
z_error(char * msg)54 void z_error(char * msg) {
55 fprintf(stderr, "%s\n", msg);
56 exit(1);
57 }
58 #endif
59 /// returns current time representation string
getDateTimeString(time_t t)60 static lString32 getDateTimeString( time_t t )
61 {
62 tm * bt = localtime(&t);
63 char str[32];
64 #ifdef _LINUX
65 snprintf(str, 32,
66 #else
67 sprintf(str,
68 #endif
69 "%04d/%02d/%02d %02d:%02d", bt->tm_year+1900, bt->tm_mon+1, bt->tm_mday, bt->tm_hour, bt->tm_min);
70 str[31] = 0;
71 return Utf8ToUnicode( lString8( str ) );
72 }
73
74 #if 0
75 static lString32 extractDocSeriesReverse( ldomDocument * doc, int & seriesNumber )
76 {
77 seriesNumber = 0;
78 lString32 res;
79 ldomXPointer p = doc->createXPointer(L"/FictionBook/description/title-info/sequence");
80 if ( p.isNull() )
81 return res;
82 ldomNode * series = p.getNode();
83 if ( series ) {
84 lString32 sname = series->getAttributeValue( attr_name );
85 lString32 snumber = series->getAttributeValue( attr_number );
86 if ( !sname.empty() ) {
87 res << L"(";
88 if ( !snumber.empty() ) {
89 res << L"#" << snumber << L" ";
90 seriesNumber = snumber.atoi();
91 }
92 res << sname;
93 res << L")";
94 }
95 }
96 return res;
97 }
98 #endif
99
100 class BookProperties
101 {
102 public:
103 lString32 filename;
104 lString32 title;
105 lString32 author;
106 lString32 series;
107 int filesize;
108 lString32 filedate;
109 int seriesNumber;
110 lString32 language;
111 lUInt32 crc32;
112 lString32 keywords;
113 lString32 description;
114 doc_format_t format;
115 };
116
GetEPUBBookProperties(const char * name,LVStreamRef stream,BookProperties * pBookProps)117 static bool GetEPUBBookProperties(const char *name, LVStreamRef stream, BookProperties * pBookProps)
118 {
119 LVContainerRef arc = LVOpenArchieve(stream );
120 if ( arc.isNull() )
121 return false; // not a ZIP archive
122
123 // check root media type
124 lString32 rootfilePath = EpubGetRootFilePath(arc);
125 if ( rootfilePath.empty() )
126 return false;
127
128 lString32 codeBase;
129 codeBase=LVExtractPath(rootfilePath, false);
130
131 LVStreamRef content_stream = arc->OpenStream(rootfilePath.c_str(), LVOM_READ);
132 if ( content_stream.isNull() )
133 return false;
134
135 ldomDocument * doc = LVParseXMLStream( content_stream );
136 if ( !doc )
137 return false;
138
139 time_t t = (time_t)time(0);
140 struct stat fs;
141 if ( !stat( name, &fs ) ) {
142 t = fs.st_mtime;
143 }
144
145 lString32 author = doc->textFromXPath( lString32("package/metadata/creator")).trim();
146 lString32 title = doc->textFromXPath( lString32("package/metadata/title")).trim();
147 lString32 language = doc->textFromXPath( lString32("package/metadata/language")).trim();
148 // There may be multiple <dc:subject> tags, which are usually used for keywords, categories
149 bool subjects_set = false;
150 lString32 subjects;
151 for ( size_t i=1; i<=EPUB_META_MAX_ITER; i++ ) {
152 ldomNode * item = doc->nodeFromXPath(lString32("package/metadata/subject[") << fmt::decimal(i) << "]");
153 if (!item)
154 break;
155 lString32 subject = item->getText().trim();
156 if (subjects_set) {
157 subjects << "\n" << subject;
158 }
159 else {
160 subjects << subject;
161 subjects_set = true;
162 }
163 }
164 lString32 description = doc->textFromXPath( cs32("package/metadata/description")).trim();
165 pBookProps->author = author;
166 pBookProps->title = title;
167 pBookProps->language = language;
168 pBookProps->keywords = subjects;
169 pBookProps->description = description;
170
171 for ( int i=1; i<20; i++ ) {
172 ldomNode * item = doc->nodeFromXPath( lString32("package/metadata/meta[") << fmt::decimal(i) << "]" );
173 if ( !item )
174 break;
175 lString32 name = item->getAttributeValue("name");
176 lString32 content = item->getAttributeValue("content");
177 if (name == "calibre:series")
178 pBookProps->series = content.trim();
179 else if (name == "calibre:series_index")
180 pBookProps->seriesNumber = content.trim().atoi();
181 }
182
183 pBookProps->filesize = (long)stream->GetSize();
184 pBookProps->filename = lString32(name);
185 pBookProps->filedate = getDateTimeString( t );
186 pBookProps->crc32 = stream->getcrc32();
187
188 delete doc;
189
190 return true;
191 }
192
GetFB3BookProperties(const char * name,LVStreamRef stream,BookProperties * pBookProps)193 static bool GetFB3BookProperties(const char *name, LVStreamRef stream, BookProperties * pBookProps)
194 {
195 LVContainerRef arc = LVOpenArchieve( stream );
196 if ( arc.isNull() )
197 return false; // not a ZIP archive
198
199 OpcPackage package(arc);
200
201 fb3ImportContext context(&package);
202
203 CRPropRef doc_props = LVCreatePropsContainer();
204 package.readCoreProperties(doc_props);
205 pBookProps->title = doc_props->getStringDef(DOC_PROP_TITLE, "");
206 pBookProps->author = doc_props->getStringDef(DOC_PROP_AUTHORS, "");
207 pBookProps->description = doc_props->getStringDef(DOC_PROP_DESCRIPTION, "");
208
209 ldomDocument * descDoc = context.getDescription();
210 if ( descDoc ) {
211 pBookProps->language = descDoc->textFromXPath( cs32("fb3-description/lang") );
212 } else {
213 CRLog::error("Couldn't parse description doc");
214 }
215
216 time_t t = (time_t)time(0);
217 struct stat fs;
218 if ( !stat( name, &fs ) ) {
219 t = fs.st_mtime;
220 }
221 pBookProps->filesize = (long)stream->GetSize();
222 pBookProps->filename = lString32(name);
223 pBookProps->filedate = getDateTimeString( t );
224 pBookProps->crc32 = stream->getcrc32();
225 return true;
226 }
227
GetDOCXBookProperties(const char * name,LVStreamRef stream,BookProperties * pBookProps)228 static bool GetDOCXBookProperties(const char *name, LVStreamRef stream, BookProperties * pBookProps)
229 {
230 LVContainerRef arc = LVOpenArchieve( stream );
231 if ( arc.isNull() )
232 return false; // not a ZIP archive
233
234 OpcPackage package(arc);
235
236 CRPropRef doc_props = LVCreatePropsContainer();
237 package.readCoreProperties(doc_props);
238 pBookProps->title = doc_props->getStringDef(DOC_PROP_TITLE, "");
239 pBookProps->author = doc_props->getStringDef(DOC_PROP_AUTHORS, "");
240 pBookProps->description = doc_props->getStringDef(DOC_PROP_DESCRIPTION, "");
241 pBookProps->language = doc_props->getStringDef(DOC_PROP_LANGUAGE, "");
242
243 time_t t = (time_t)time(0);
244 struct stat fs;
245 if ( !stat( name, &fs ) ) {
246 t = fs.st_mtime;
247 }
248 pBookProps->filesize = (long)stream->GetSize();
249 pBookProps->filename = lString32(name);
250 pBookProps->filedate = getDateTimeString( t );
251 pBookProps->crc32 = stream->getcrc32();
252
253 return true;
254 }
255
GetODTBookProperties(const char * name,LVStreamRef stream,BookProperties * pBookProps)256 static bool GetODTBookProperties(const char *name, LVStreamRef stream, BookProperties * pBookProps)
257 {
258 LVContainerRef arc = LVOpenArchieve( stream );
259 if ( arc.isNull() )
260 return false; // not a ZIP archive
261
262 OpcPackage package(arc);
263
264 //Read document metadata
265 LVStreamRef meta_stream = arc->OpenStream(U"meta.xml", LVOM_READ);
266 if ( meta_stream.isNull() )
267 return false;
268 ldomDocument * metaDoc = LVParseXMLStream( meta_stream );
269 if ( !metaDoc ) {
270 CRLog::error("Couldn't parse document meta data");
271 return false;
272 } else {
273 CRPropRef doc_props = LVCreatePropsContainer();
274
275 lString32 author = metaDoc->textFromXPath( cs32("document-meta/meta/creator") );
276 lString32 title = metaDoc->textFromXPath( cs32("document-meta/meta/title") );
277 lString32 description = metaDoc->textFromXPath( cs32("document-meta/meta/description") );
278 doc_props->setString(DOC_PROP_TITLE, title);
279 doc_props->setString(DOC_PROP_AUTHORS, author );
280 doc_props->setString(DOC_PROP_DESCRIPTION, description );
281 delete metaDoc;
282 }
283
284 time_t t = (time_t)time(0);
285 struct stat fs;
286 if ( !stat( name, &fs ) ) {
287 t = fs.st_mtime;
288 }
289 pBookProps->filesize = (long)stream->GetSize();
290 pBookProps->filename = lString32(name);
291 pBookProps->filedate = getDateTimeString( t );
292 pBookProps->crc32 = stream->getcrc32();
293
294 return true;
295 }
296
GetBookProperties(const char * name,BookProperties * pBookProps)297 static bool GetBookProperties(const char *name, BookProperties * pBookProps)
298 {
299 CRLog::trace("GetBookProperties( %s )", name);
300
301 // check archieve
302 lString32 arcPathName;
303 lString32 arcItemPathName;
304 bool isArchiveFile = LVSplitArcName( lString32(name), arcPathName, arcItemPathName );
305
306 // open stream
307 LVStreamRef stream = LVOpenFileStream( (isArchiveFile ? arcPathName : Utf8ToUnicode(lString8(name))).c_str() , LVOM_READ);
308 if (!stream) {
309 CRLog::error("cannot open file %s", name);
310 return false;
311 }
312
313
314 pBookProps->format = doc_format_none;
315 if ( DetectEpubFormat( stream ) ) {
316 CRLog::trace("GetBookProperties() : epub format detected");
317 pBookProps->format = doc_format_epub;
318 return GetEPUBBookProperties( name, stream, pBookProps );
319 }
320 if ( DetectFb3Format( stream ) ) {
321 CRLog::trace("GetBookProperties() : fb3 format detected");
322 pBookProps->format = doc_format_fb3;
323 return GetFB3BookProperties( name, stream, pBookProps );
324 }
325 if ( DetectDocXFormat( stream ) ) {
326 CRLog::trace("GetBookProperties() : docx format detected");
327 pBookProps->format = doc_format_docx;
328 return GetDOCXBookProperties( name, stream, pBookProps );
329 }
330 if ( DetectOpenDocumentFormat( stream ) ) {
331 CRLog::trace("GetBookProperties() : odt format detected");
332 pBookProps->format = doc_format_odt;
333 return GetODTBookProperties( name, stream, pBookProps );
334 }
335
336 time_t t = (time_t)time(0);
337
338 if ( isArchiveFile ) {
339 int arcsize = (int)stream->GetSize();
340 LVContainerRef container = LVOpenArchieve(stream);
341 if ( container.isNull() ) {
342 CRLog::error( "Cannot read archive contents from %s", LCSTR(arcPathName) );
343 return false;
344 }
345 stream = container->OpenStream(arcItemPathName.c_str(), LVOM_READ);
346 if ( stream.isNull() ) {
347 CRLog::error( "Cannot open archive file item stream %s", LCSTR(lString32(name)) );
348 return false;
349 }
350 }
351 struct stat fs;
352 if ( !stat( name, &fs ) ) {
353 t = fs.st_mtime;
354 }
355
356 // read document
357 #if COMPACT_DOM==1
358 ldomDocument doc(stream, 0);
359 #else
360 ldomDocument doc;
361 #endif
362 ldomDocumentWriter writer(&doc, true);
363 doc.setNodeTypes( fb2_elem_table );
364 doc.setAttributeTypes( fb2_attr_table );
365 doc.setNameSpaceTypes( fb2_ns_table );
366 LVXMLParser parser( stream, &writer );
367 CRLog::trace( "checking format..." );
368 if ( !parser.CheckFormat() ) {
369 return false;
370 }
371 CRLog::trace( "parsing..." );
372 if ( !parser.Parse() ) {
373 return false;
374 }
375 CRLog::trace( "parsed" );
376 #if 0
377 char ofname[512];
378 sprintf(ofname, "%s.xml", name);
379 CRLog::trace(" writing to file %s", ofname);
380 LVStreamRef out = LVOpenFileStream(ofname, LVOM_WRITE);
381 doc.saveToStream(out, "utf16");
382 #endif
383 lString32 authors = extractDocAuthors( &doc, lString32("|"), false );
384 lString32 title = extractDocTitle( &doc );
385 lString32 language = extractDocLanguage( &doc );
386 lString32 series = extractDocSeries( &doc, &pBookProps->seriesNumber );
387 lString32 keywords = extractDocKeywords( &doc );
388 lString32 description = extractDocDescription( &doc );
389 #if SERIES_IN_AUTHORS==1
390 if ( !series.empty() )
391 authors << " " << series;
392 #endif
393 pBookProps->format = doc_format_fb2;
394 pBookProps->title = title;
395 pBookProps->author = authors;
396 pBookProps->series = series;
397 pBookProps->filesize = (long)stream->GetSize();
398 pBookProps->filename = lString32(name);
399 pBookProps->filedate = getDateTimeString( t );
400 pBookProps->language = language;
401 pBookProps->keywords = keywords;
402 pBookProps->description = description;
403 pBookProps->crc32 = stream->getcrc32();
404 return true;
405 }
406
407
408 /*
409 * Class: org_coolreader_crengine_Engine
410 * Method: scanBookPropertiesInternal
411 * Signature: (Lorg/coolreader/crengine/FileInfo;)Z
412 */
Java_org_coolreader_crengine_Engine_scanBookPropertiesInternal(JNIEnv * _env,jclass _engine,jobject _fileInfo)413 JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_scanBookPropertiesInternal
414 (JNIEnv * _env, jclass _engine, jobject _fileInfo)
415 {
416 CRJNIEnv env(_env);
417 jclass objclass = env->GetObjectClass(_fileInfo);
418 jfieldID fid = env->GetFieldID(objclass, "pathname", "Ljava/lang/String;");
419 lString32 filename = env.fromJavaString( (jstring)env->GetObjectField(_fileInfo, fid) );
420 fid = env->GetFieldID(objclass, "arcname", "Ljava/lang/String;");
421 lString32 arcname = env.fromJavaString( (jstring)env->GetObjectField(_fileInfo, fid) );
422 if ( filename.empty() )
423 return JNI_FALSE;
424 if ( !arcname.empty() )
425 filename = arcname + "@/" + filename;
426
427 BookProperties props;
428 CRLog::debug("Looking for properties of file %s", LCSTR(filename));
429 bool res = GetBookProperties(LCSTR(filename), &props);
430 if ( !res )
431 return JNI_FALSE;
432 #define SET_STR_FLD(fldname,src) \
433 { \
434 jfieldID fid = env->GetFieldID(objclass, fldname, "Ljava/lang/String;"); \
435 env->SetObjectField(_fileInfo,fid,env.toJavaString(src)); \
436 }
437 #define SET_INT_FLD(fldname,src) \
438 { \
439 jfieldID fid = env->GetFieldID(objclass, fldname, "I"); \
440 env->SetIntField(_fileInfo,fid,src); \
441 }
442 #define SET_LONG_FLD(fldname,src) \
443 { \
444 jfieldID fid = env->GetFieldID(objclass, fldname, "J"); \
445 env->SetLongField(_fileInfo,fid,src); \
446 }
447 SET_STR_FLD("title",props.title);
448 SET_STR_FLD("authors",props.author);
449 SET_STR_FLD("series",props.series);
450 SET_INT_FLD("seriesNumber",props.seriesNumber);
451 SET_STR_FLD("language",props.language);
452 SET_LONG_FLD("crc32",props.crc32);
453 if (doc_format_fb2 == props.format) {
454 // TODO: may be fb3 too...
455 // keywords separated by "\n", see lvtinydom.cpp:
456 // lString32 extractDocKeywords( ldomDocument * doc )
457 int pos = props.keywords.pos('\n');
458 while (pos > 0) {
459 props.keywords[pos] = '|';
460 pos = props.keywords.pos('\n', pos + 1);
461 }
462 SET_STR_FLD("genres", props.keywords);
463 }
464 SET_STR_FLD("description",props.description);
465
466 return JNI_TRUE;
467 }
468
469 /*
470 * Class: org_coolreader_crengine_Engine
471 * Method: updateFileCRC32Internal
472 * Signature: (Lorg/coolreader/crengine/FileInfo;)Z
473 */
Java_org_coolreader_crengine_Engine_updateFileCRC32Internal(JNIEnv * _env,jclass _engine,jobject _fileInfo)474 JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_updateFileCRC32Internal
475 (JNIEnv * _env, jclass _engine, jobject _fileInfo)
476 {
477 CRJNIEnv env(_env);
478 jclass objclass = env->GetObjectClass(_fileInfo);
479 jfieldID fid = env->GetFieldID(objclass, "pathname", "Ljava/lang/String;");
480 lString32 filename = env.fromJavaString( (jstring)env->GetObjectField(_fileInfo, fid) );
481 fid = env->GetFieldID(objclass, "arcname", "Ljava/lang/String;");
482 lString32 arcname = env.fromJavaString( (jstring)env->GetObjectField(_fileInfo, fid) );
483 if ( filename.empty() )
484 return JNI_FALSE;
485 bool isArchiveFile = !arcname.empty();
486 // open stream
487 LVStreamRef stream = LVOpenFileStream( (isArchiveFile ? arcname : filename).c_str() , LVOM_READ );
488 if (!stream.isNull()) {
489 if (isArchiveFile) {
490 LVContainerRef container = LVOpenArchieve(stream);
491 if (!container.isNull()) {
492 stream = container->OpenStream(filename.c_str(), LVOM_READ);
493 if (stream.isNull()) {
494 CRLog::error("Cannot open archive file item stream %s", LCSTR(filename));
495 }
496 } else {
497 CRLog::error("Cannot read archive contents from %s", LCSTR(arcname));
498 stream = LVStreamRef();
499 }
500 }
501 }
502 if (!stream.isNull()) {
503 fid = env->GetFieldID(objclass, "crc32", "J");
504 env->SetLongField(_fileInfo, fid, stream->getcrc32());
505 } else {
506 CRLog::error("cannot open file %s", LCSTR(isArchiveFile ? arcname : filename));
507 return JNI_FALSE;
508 }
509 return JNI_TRUE;
510 }
511
512
drawBookCoverInternal(JNIEnv * _env,jclass _engine,jobject bitmap,jbyteArray _data,jstring _fontFace,jstring _title,jstring _authors,jstring _seriesName,jint seriesNumber,jint bpp)513 void drawBookCoverInternal(JNIEnv * _env, jclass _engine, jobject bitmap, jbyteArray _data, jstring _fontFace, jstring _title, jstring _authors, jstring _seriesName, jint seriesNumber, jint bpp)
514 {
515 CRJNIEnv env(_env);
516 CRLog::debug("drawBookCoverInternal called");
517 lString8 fontFace = UnicodeToUtf8(env.fromJavaString(_fontFace));
518 lString32 title = env.fromJavaString(_title);
519 lString32 authors = env.fromJavaString(_authors);
520 lString32 seriesName = env.fromJavaString(_seriesName);
521 LVStreamRef stream;
522 LVDrawBuf * drawbuf = BitmapAccessorInterface::getInstance()->lock(_env, bitmap);
523 if (drawbuf != NULL) {
524 LVImageSourceRef image;
525 if (_data != NULL && _env->GetArrayLength(_data) > 0) {
526 CRLog::debug("drawBookCoverInternal : cover image from array");
527 stream = env.jbyteArrayToStream(_data);
528 if (!stream.isNull())
529 image = LVCreateStreamImageSource(stream);
530 }
531
532 int factor = 1;
533 int dx = drawbuf->GetWidth();
534 int dy = drawbuf->GetHeight();
535 int MIN_WIDTH = 300;
536 int MIN_HEIGHT = 400;
537 if (dx < MIN_WIDTH || dy < MIN_HEIGHT) {
538 if (dx * 2 < MIN_WIDTH || dy * 2 < MIN_HEIGHT) {
539 dx *= 3;
540 dy *= 3;
541 factor = 3;
542 } else {
543 dx *= 2;
544 dy *= 2;
545 factor = 2;
546 }
547 }
548 LVDrawBuf * drawbuf2 = drawbuf;
549 if (factor > 1)
550 drawbuf2 = new LVColorDrawBuf(dx, dy, drawbuf->GetBitsPerPixel());
551
552 if (bpp >= 16) {
553 // native color resolution
554 CRLog::debug("drawBookCoverInternal : calling LVDrawBookCover");
555 LVDrawBookCover(*drawbuf2, image, fontFace, title, authors, seriesName, seriesNumber);
556 image.Clear();
557 } else {
558 LVGrayDrawBuf grayBuf(drawbuf2->GetWidth(), drawbuf2->GetHeight(), bpp);
559 LVDrawBookCover(grayBuf, image, fontFace, title, authors, seriesName, seriesNumber);
560 image.Clear();
561 grayBuf.DrawTo(drawbuf2, 0, 0, 0, NULL);
562 }
563
564 if (factor > 1) {
565 CRLog::debug("drawBookCoverInternal : rescaling");
566 drawbuf->DrawRescaled(drawbuf2, 0, 0, drawbuf->GetWidth(), drawbuf->GetHeight(), 0);
567 delete drawbuf2;
568 }
569
570 //CRLog::trace("getPageImageInternal calling bitmap->unlock");
571 BitmapAccessorInterface::getInstance()->unlock(_env, bitmap, drawbuf);
572 } else {
573 CRLog::error("bitmap accessor is invalid");
574 }
575 CRLog::debug("drawBookCoverInternal finished");
576 }
577
578 /*
579 * Class: org_coolreader_crengine_Engine
580 * Method: drawBookCoverInternal
581 * Signature: (Landroid/graphics/Bitmap;[BLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V
582 */
Java_org_coolreader_crengine_Engine_drawBookCoverInternal(JNIEnv * _env,jclass _engine,jobject bitmap,jbyteArray _data,jstring _fontFace,jstring _title,jstring _authors,jstring _seriesName,jint seriesNumber,jint bpp)583 JNIEXPORT void JNICALL Java_org_coolreader_crengine_Engine_drawBookCoverInternal
584 (JNIEnv * _env, jclass _engine, jobject bitmap, jbyteArray _data, jstring _fontFace, jstring _title, jstring _authors, jstring _seriesName, jint seriesNumber, jint bpp)
585 {
586 COFFEE_TRY_JNI(_env, drawBookCoverInternal(_env, _engine, bitmap, _data, _fontFace, _title, _authors, _seriesName, seriesNumber, bpp));
587 }
588
scanBookCoverInternal(JNIEnv * _env,jclass _class,jstring _path)589 jbyteArray scanBookCoverInternal
590 (JNIEnv * _env, jclass _class, jstring _path)
591 {
592 CRJNIEnv env(_env);
593 lString32 path = env.fromJavaString(_path);
594 CRLog::debug("scanBookCoverInternal(%s) called", LCSTR(path));
595 lString32 arcname, item;
596 LVStreamRef res;
597 jbyteArray array = NULL;
598 LVContainerRef arc;
599 if (!LVSplitArcName(path, arcname, item)) {
600 // not in archive
601 LVStreamRef stream = LVOpenFileStream(path.c_str(), LVOM_READ);
602 if (!stream.isNull()) {
603 arc = LVOpenArchieve(stream);
604 if (!arc.isNull()) {
605 // ZIP-based format
606 if (DetectEpubFormat(stream)) {
607 // EPUB
608 // extract coverpage from epub
609 res = GetEpubCoverpage(arc);
610 }
611 } else {
612 res = GetFB2Coverpage(stream);
613 if (res.isNull()) {
614 doc_format_t fmt;
615 if (DetectPDBFormat(stream, fmt)) {
616 res = GetPDBCoverpage(stream);
617 }
618 }
619 }
620 }
621 } else {
622 CRLog::debug("scanBookCoverInternal() : is archive, item=%s, arc=%s", LCSTR(item), LCSTR(arcname));
623 LVStreamRef arcstream = LVOpenFileStream(arcname.c_str(), LVOM_READ);
624 if (!arcstream.isNull()) {
625 arc = LVOpenArchieve(arcstream);
626 if (!arc.isNull()) {
627 LVStreamRef stream = arc->OpenStream(item.c_str(), LVOM_READ);
628 if (!stream.isNull()) {
629 CRLog::debug("scanBookCoverInternal() : archive stream opened ok, parsing");
630 res = GetFB2Coverpage(stream);
631 if (res.isNull()) {
632 doc_format_t fmt;
633 if (DetectPDBFormat(stream, fmt)) {
634 res = GetPDBCoverpage(stream);
635 }
636 }
637 }
638 }
639 }
640 }
641 if (!res.isNull())
642 array = env.streamToJByteArray(res);
643 if (array != NULL)
644 CRLog::debug("scanBookCoverInternal() : returned cover page array");
645 else
646 CRLog::debug("scanBookCoverInternal() : cover page data not found");
647 return array;
648 }
649
650 /*
651 * Class: org_coolreader_crengine_Engine
652 * Method: scanBookCoverInternal
653 * Signature: (Ljava/lang/String;)[B
654 */
Java_org_coolreader_crengine_Engine_scanBookCoverInternal(JNIEnv * _env,jclass _class,jstring _path)655 JNIEXPORT jbyteArray JNICALL Java_org_coolreader_crengine_Engine_scanBookCoverInternal
656 (JNIEnv * _env, jclass _class, jstring _path)
657 {
658 jbyteArray res = NULL;
659 COFFEE_TRY_JNI(_env, res = scanBookCoverInternal( _env, _class, _path));
660 return res;
661 }
662
663 /*
664 * Class: org_coolreader_crengine_Engine
665 * Method: getArchiveItemsInternal
666 * Signature: (Ljava/lang/String;)[Ljava/lang/String;
667 */
Java_org_coolreader_crengine_Engine_getArchiveItemsInternal(JNIEnv * _env,jclass,jstring jarcName)668 JNIEXPORT jobjectArray JNICALL Java_org_coolreader_crengine_Engine_getArchiveItemsInternal
669 (JNIEnv * _env, jclass, jstring jarcName)
670 {
671 CRJNIEnv env(_env);
672 lString32 arcName = env.fromJavaString(jarcName);
673 lString32Collection list;
674
675 //fontMan->getFaceList(list);
676 LVStreamRef stream = LVOpenFileStream( arcName.c_str(), LVOM_READ );
677 if ( !stream.isNull() ) {
678 LVContainerRef arc = LVOpenArchieve(stream);
679 if ( !arc.isNull() ) {
680 // convert
681 for ( int i=0; i<arc->GetObjectCount(); i++ ) {
682 const LVContainerItemInfo * item = arc->GetObjectInfo(i);
683 if ( item->IsContainer())
684 continue;
685 list.add( item->GetName() );
686 list.add( lString32::itoa(item->GetSize()) );
687 }
688 }
689 }
690 return env.toJavaStringArray(list);
691 }
692
693
694 class JNICDRLogger : public CRLog
695 {
696 public:
JNICDRLogger()697 JNICDRLogger()
698 {
699 curr_level = CRLog::LL_DEBUG;
700 }
701 protected:
702
log(const char * lvl,const char * msg,va_list args)703 virtual void log( const char * lvl, const char * msg, va_list args)
704 {
705 #define MAX_LOG_MSG_SIZE 1024
706 static char buffer[MAX_LOG_MSG_SIZE+1];
707 vsnprintf(buffer, MAX_LOG_MSG_SIZE, msg, args);
708 int level = ANDROID_LOG_DEBUG;
709 //LOGD("CRLog::log is called with LEVEL %s, pattern %s", lvl, msg);
710 if ( !strcmp(lvl, "FATAL") )
711 level = ANDROID_LOG_FATAL;
712 else if ( !strcmp(lvl, "ERROR") )
713 level = ANDROID_LOG_ERROR;
714 else if ( !strcmp(lvl, "WARN") )
715 level = ANDROID_LOG_WARN;
716 else if ( !strcmp(lvl, "INFO") )
717 level = ANDROID_LOG_INFO;
718 else if ( !strcmp(lvl, "DEBUG") )
719 level = ANDROID_LOG_DEBUG;
720 else if ( !strcmp(lvl, "TRACE") )
721 level = ANDROID_LOG_VERBOSE;
722 __android_log_write(level, LOG_TAG, buffer);
723 }
724 };
725
726 //typedef void (lv_FatalErrorHandler_t)(int errorCode, const char * errorText );
727
cr3androidFatalErrorHandler(int errorCode,const char * errorText)728 void cr3androidFatalErrorHandler(int errorCode, const char * errorText )
729 {
730 LOGE("CoolReader Fatal Error #%d: %s", errorCode, errorText);
731 LOGASSERTFAILED("CoolReader Fatal Error", "CoolReader Fatal Error #%d: %s", errorCode, errorText);
732 //static char str[1001];
733 //snprintf(str, 1000, "CoolReader Fatal Error #%d: %s", errorCode, errorText);
734 //LOGE("CoolReader Fatal Error #%d: %s", errorCode, errorText);
735 //LOGASSERTFAILED(errorText, "CoolReader Fatal Error #%d: %s", errorCode, errorText);
736 }
737
738 /// set fatal error handler
739 void crSetFatalErrorHandler( lv_FatalErrorHandler_t * handler );
740
initInternal(JNIEnv * penv,jclass obj,jobjectArray fontArray,jint sdk_int)741 jboolean initInternal(JNIEnv * penv, jclass obj, jobjectArray fontArray, jint sdk_int) {
742
743 CRJNIEnv::sdk_int = sdk_int;
744
745 CRJNIEnv env(penv);
746
747 // to catch crashes and remove current cache file on crash (SIGSEGV etc.)
748 crSetSignalHandler();
749
750 LOGI("initInternal called");
751 // set fatal error handler
752 crSetFatalErrorHandler( &cr3androidFatalErrorHandler );
753 LOGD("Redirecting CDRLog to Android");
754 CRLog::setLogger( new JNICDRLogger() );
755 CRLog::setLogLevel( CRLog::LL_TRACE );
756 CRLog::info("CREngine log redirected");
757 CRLog::info("CRENGINE version %s %s", CR_ENGINE_VERSION, CR_ENGINE_BUILD_DATE);
758
759 CRLog::info("initializing hyphenation manager");
760 HyphMan::initDictionaries(lString32::empty_str); //don't look for dictionaries
761 HyphMan::activateDictionary(lString32(HYPH_DICT_ID_NONE));
762 CRLog::info("creating font manager");
763 InitFontManager(lString8::empty_str);
764 CRLog::debug("converting fonts array: %d items", (int)env->GetArrayLength(fontArray));
765 lString32Collection fonts;
766 env.fromJavaStringArray(fontArray, fonts);
767 int len = fonts.length();
768 CRLog::debug("registering fonts: %d fonts in list", len);
769 for ( int i=0; i<len; i++ ) {
770 lString8 fontName = UnicodeToUtf8(fonts[i]);
771 CRLog::debug("registering font %s", fontName.c_str());
772 if ( !fontMan->RegisterFont( fontName ) )
773 CRLog::error("cannot load font %s", fontName.c_str());
774 }
775 CRLog::info("%d fonts registered", fontMan->GetFontCount());
776 return fontMan->GetFontCount() ? JNI_TRUE : JNI_FALSE;
777 }
778
779 /*
780 * Class: org_coolreader_crengine_Engine
781 * Method: initInternal
782 * Signature: ([Ljava/lang/String;I)Z
783 */
Java_org_coolreader_crengine_Engine_initInternal(JNIEnv * penv,jclass obj,jobjectArray fontArray,jint sdk_int)784 JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_initInternal
785 (JNIEnv * penv, jclass obj, jobjectArray fontArray, jint sdk_int)
786 {
787 jboolean res = JNI_FALSE;
788 COFFEE_TRY_JNI(penv, res = initInternal(penv, obj, fontArray, sdk_int));
789 return res;
790 }
791
792 class HyphDataLoaderProxy : public HyphDataLoader {
793 JavaVM *mJavaVM;
794 public:
HyphDataLoaderProxy(JavaVM * jvm)795 HyphDataLoaderProxy(JavaVM *jvm) :
796 HyphDataLoader(), mJavaVM(jvm) {
797 }
798
~HyphDataLoaderProxy()799 virtual ~HyphDataLoaderProxy() {}
800
loadData(lString32 id)801 virtual LVStreamRef loadData(lString32 id) {
802 JNIEnv *penv = NULL;
803 bool attached = false;
804 mJavaVM->GetEnv((void **) &penv, JNI_VERSION_1_6);
805 if (NULL == penv) {
806 // caller thread is not attached yet
807 mJavaVM->AttachCurrentThread(&penv, NULL);
808 attached = true;
809 }
810 LVStreamRef stream = LVStreamRef();
811 jclass pjcEngine = penv->FindClass("org/coolreader/crengine/Engine");
812 if (NULL == pjcEngine)
813 return stream;
814 jmethodID pjmEngine_loadHyphDictData = penv->GetStaticMethodID(pjcEngine, "loadHyphDictData", "(Ljava/lang/String;)[B");
815 if (NULL == pjmEngine_loadHyphDictData)
816 return stream;
817 CRJNIEnv env(penv);
818 jstring jid = env.toJavaString(id);
819 jbyteArray data = static_cast<jbyteArray>(penv->CallStaticObjectMethod(pjcEngine, pjmEngine_loadHyphDictData, jid));
820 stream = env.jbyteArrayToStream(data);
821 if (attached)
822 mJavaVM->DetachCurrentThread();
823 return stream;
824 }
825 };
826
initDictionaries(JNIEnv * penv,jclass clazz,jobjectArray dictArray)827 jboolean initDictionaries(JNIEnv *penv, jclass clazz, jobjectArray dictArray) {
828 jclass pjcHyphDict = penv->FindClass("org/coolreader/crengine/Engine$HyphDict");
829 if (NULL == pjcHyphDict)
830 return JNI_FALSE;
831 jfieldID pjfHyphDict_type = penv->GetFieldID(pjcHyphDict, "type", "I");
832 if (NULL == pjfHyphDict_type)
833 return JNI_FALSE;
834 jfieldID pjfHyphDict_code = penv->GetFieldID(pjcHyphDict, "code", "Ljava/lang/String;");
835 if (NULL == pjfHyphDict_code)
836 return JNI_FALSE;
837
838 int len = penv->GetArrayLength(dictArray);
839 HyphDictionary *dict;
840 CRJNIEnv env(penv);
841 HyphDictType dict_type;
842 for (int i = 0; i < len; i++) {
843 jobject obj = penv->GetObjectArrayElement(dictArray, i);
844 int type = penv->GetIntField(obj, pjfHyphDict_type);
845 jstring code = static_cast<jstring>(penv->GetObjectField(obj, pjfHyphDict_code));
846 switch (type) { // convert org/coolreader/crengine/Engine$HyphDict$type into HyphDictType
847 case 0: // org/coolreader/crengine/Engine$HYPH_NONE
848 dict_type = HDT_NONE;
849 break;
850 case 1: // org/coolreader/crengine/Engine$HYPH_ALGO
851 dict_type = HDT_ALGORITHM;
852 break;
853 case 2: // org/coolreader/crengine/Engine$HYPH_DICT
854 dict_type = HDT_DICT_TEX;
855 break;
856 default:
857 dict_type = HDT_NONE;
858 break;
859 }
860 lString32 dict_code = env.fromJavaString(code);
861 dict = new HyphDictionary(dict_type, dict_code, dict_code, dict_code);
862 if (!HyphMan::addDictionaryItem(dict))
863 delete dict;
864 }
865 JavaVM *jvm;
866 env->GetJavaVM(&jvm);
867 HyphMan::setDataLoader(new HyphDataLoaderProxy( jvm ));
868 return JNI_TRUE;
869 }
870
871 JNIEXPORT jboolean JNICALL
Java_org_coolreader_crengine_Engine_initDictionaries(JNIEnv * penv,jclass clazz,jobjectArray dictArray)872 Java_org_coolreader_crengine_Engine_initDictionaries
873 (JNIEnv * penv, jclass clazz, jobjectArray dictArray)
874 {
875 jboolean res = JNI_FALSE;
876 COFFEE_TRY_JNI(penv, res = initDictionaries(penv, clazz, dictArray));
877 return res;
878 }
879
880 /*
881 * Class: org_coolreader_crengine_Engine
882 * Method: uninitInternal
883 * Signature: ()V
884 */
Java_org_coolreader_crengine_Engine_uninitInternal(JNIEnv *,jclass)885 JNIEXPORT void JNICALL Java_org_coolreader_crengine_Engine_uninitInternal
886 (JNIEnv *, jclass)
887 {
888 LOGI("uninitInternal called");
889 HyphMan::uninit();
890 ShutdownFontManager();
891 CRLog::setLogger(NULL);
892 }
893
894 /*
895 * Class: org_coolreader_crengine_Engine
896 * Method: getFontFaceListInternal
897 * Signature: ()[Ljava/lang/String;
898 */
Java_org_coolreader_crengine_Engine_getFontFaceListInternal(JNIEnv * penv,jclass obj)899 JNIEXPORT jobjectArray JNICALL Java_org_coolreader_crengine_Engine_getFontFaceListInternal
900 (JNIEnv * penv, jclass obj)
901 {
902 LOGI("getFontFaceListInternal called");
903 CRJNIEnv env(penv);
904 lString32Collection list;
905 COFFEE_TRY_JNI(penv, fontMan->getFaceList(list));
906 return env.toJavaStringArray(list);
907 }
908
909 /*
910 * Class: org_coolreader_crengine_Engine
911 * Method: getFontFileNameListInternal
912 * Signature: ()[Ljava/lang/String;
913 */
Java_org_coolreader_crengine_Engine_getFontFileNameListInternal(JNIEnv * penv,jclass cls)914 JNIEXPORT jobjectArray JNICALL Java_org_coolreader_crengine_Engine_getFontFileNameListInternal
915 (JNIEnv * penv, jclass cls)
916 {
917 LOGI("getFontFileListInternal called");
918 CRJNIEnv env(penv);
919 lString32Collection list;
920 COFFEE_TRY_JNI(penv, fontMan->getFontFileNameList(list));
921 return env.toJavaStringArray(list);
922 }
923
924 /*
925 * Class: org_coolreader_crengine_Engine
926 * Method: setCacheDirectoryInternal
927 * Signature: (Ljava/lang/String;I)Z
928 */
Java_org_coolreader_crengine_Engine_setCacheDirectoryInternal(JNIEnv * penv,jclass obj,jstring dir,jint size)929 JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_setCacheDirectoryInternal
930 (JNIEnv * penv, jclass obj, jstring dir, jint size)
931 {
932 CRJNIEnv env(penv);
933 bool res = false;
934 COFFEE_TRY_JNI(penv, res = ldomDocCache::init(env.fromJavaString(dir), size ));
935 return res ? JNI_TRUE : JNI_FALSE;
936 }
937
938 /*
939 * Class: org_coolreader_crengine_Engine
940 * Method: haveFcLangCodeInternal
941 * Signature: (Ljava/lang/String;)Z
942 */
Java_org_coolreader_crengine_Engine_haveFcLangCodeInternal(JNIEnv * env,jclass cls,jstring langCode)943 JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_haveFcLangCodeInternal
944 (JNIEnv *env, jclass cls, jstring langCode)
945 {
946 jboolean res = JNI_FALSE;
947 const char* langCode_ptr = env->GetStringUTFChars(langCode, 0);
948 if (langCode_ptr) {
949 struct fc_lang_catalog* lang_ptr = fc_lang_cat;
950 for (int i = 0; i < fc_lang_cat_sz; i++)
951 {
952 if (strcmp(lang_ptr->lang_code, langCode_ptr) == 0)
953 {
954 res = JNI_TRUE;
955 break;
956 }
957 lang_ptr++;
958 }
959 env->ReleaseStringUTFChars(langCode, langCode_ptr);
960 }
961 return res;
962 }
963
964
965 /*
966 * Class: org_coolreader_crengine_Engine
967 * Method: checkFontLanguageCompatibilityInternal
968 * Signature: (Ljava/lang/String;Ljava/lang/String;)Z
969 */
Java_org_coolreader_crengine_Engine_checkFontLanguageCompatibilityInternal(JNIEnv * env,jclass cls,jstring fontFace,jstring langCode)970 JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_checkFontLanguageCompatibilityInternal
971 (JNIEnv *env, jclass cls, jstring fontFace, jstring langCode)
972 {
973 jboolean res = JNI_TRUE;
974 const char* fontFace_ptr = env->GetStringUTFChars(fontFace, 0);
975 const char* langCode_ptr = env->GetStringUTFChars(langCode, 0);
976 if (fontFace_ptr && langCode_ptr) {
977 res = fontMan->checkFontLangCompat(lString8(fontFace_ptr), lString8(langCode_ptr)) ? JNI_TRUE : JNI_FALSE;
978 }
979 if (langCode_ptr)
980 env->ReleaseStringUTFChars(langCode, langCode_ptr);
981 if (fontFace_ptr)
982 env->ReleaseStringUTFChars(fontFace, fontFace_ptr);
983 return res;
984 }
985
986 /*
987 * Class: org_coolreader_crengine_Engine
988 * Method: listFilesInternal
989 * Signature: (Ljava/io/File;)[Ljava/io/File;
990 */
Java_org_coolreader_crengine_Engine_listFilesInternal(JNIEnv * penv,jclass,jobject jdir)991 JNIEXPORT jobjectArray JNICALL Java_org_coolreader_crengine_Engine_listFilesInternal
992 (JNIEnv *penv, jclass, jobject jdir)
993 {
994 CRJNIEnv env(penv);
995 if (NULL == jdir)
996 return NULL;
997 jclass pjcFile = env->GetObjectClass(jdir);
998 if (NULL == pjcFile)
999 return NULL;
1000 jmethodID pjmFile_GetAbsolutePath = env->GetMethodID(pjcFile, "getAbsolutePath", "()Ljava/lang/String;");
1001 if (NULL == pjmFile_GetAbsolutePath)
1002 return NULL;
1003 jmethodID pjmFile_Ctor = env->GetMethodID(pjcFile, "<init>", "(Ljava/lang/String;)V");
1004 if (NULL == pjmFile_Ctor)
1005 return NULL;
1006 jstring jpathname = (jstring)env->CallObjectMethod(jdir, pjmFile_GetAbsolutePath);
1007 if (NULL == jpathname)
1008 return NULL;
1009 lString32 path = env.fromJavaString(jpathname);
1010 jobjectArray jarray = NULL;
1011 LVContainerRef dir = LVOpenDirectory(path);
1012 if ( !dir.isNull() ) {
1013 jstring emptyString = env->NewStringUTF("");
1014 jobject emptyFile = env->NewObject(pjcFile, pjmFile_Ctor, emptyString);
1015 jarray = env->NewObjectArray(dir->GetObjectCount(), pjcFile, emptyFile);
1016 if (NULL != jarray) {
1017 for (int i = 0; i < dir->GetObjectCount(); i++) {
1018 const LVContainerItemInfo *item = dir->GetObjectInfo(i);
1019 if (item && item->GetName()) {
1020 lString32 fileName = path + "/" + item->GetName();
1021 jstring jfilename = env.toJavaString(fileName);
1022 if (NULL != jfilename) {
1023 env->ExceptionClear();
1024 jobject jfile = env->NewObject(pjcFile, pjmFile_Ctor, jfilename);
1025 if (env->ExceptionCheck() == JNI_TRUE)
1026 env->ExceptionClear();
1027 else {
1028 if (NULL != jfile)
1029 env->SetObjectArrayElement(jarray, i, jfile);
1030 }
1031 env->DeleteLocalRef(jfile);
1032 env->DeleteLocalRef(jfilename);
1033 }
1034 }
1035 }
1036 }
1037 }
1038 return jarray;
1039 }
1040
1041 /*
1042 * Class: org_coolreader_crengine_Engine
1043 * Method: isLink
1044 * Signature: (Ljava/lang/String;)Ljava/lang/String;
1045 */
Java_org_coolreader_crengine_Engine_isLink(JNIEnv * env,jclass obj,jstring pathname)1046 JNIEXPORT jstring JNICALL Java_org_coolreader_crengine_Engine_isLink
1047 (JNIEnv * env, jclass obj, jstring pathname)
1048 {
1049 //CRLog::trace("isLink : enter");
1050 if (!pathname)
1051 return NULL;
1052 //CRLog::trace("isLink : pathname is not null");
1053 int res = JNI_FALSE;
1054 jboolean iscopy;
1055 const char * s = env->GetStringUTFChars(pathname, &iscopy);
1056 //CRLog::trace("isLink : read utf from pathname");
1057 struct stat st;
1058 lString8 path;
1059 if ( !lstat( s, &st) ) {
1060 if ( S_ISLNK(st.st_mode) ) {
1061 char buf[2048];
1062 int len = readlink(s, buf, sizeof(buf) - 1);
1063 if (len != -1) {
1064 buf[len] = 0;
1065 path = lString8(buf);
1066 }
1067 }
1068 }
1069 //CRLog::trace("isLink : releasing utf pathname");
1070 env->ReleaseStringUTFChars(pathname, s);
1071 //CRLog::trace("isLink : returning");
1072 return !path.empty() ? (jstring)env->NewGlobalRef(env->NewStringUTF(path.c_str())) : NULL;
1073 }
1074
1075
1076 /*
1077 * Class: org_coolreader_crengine_Engine
1078 * Method: suspendLongOperationInternal
1079 * Signature: ()V
1080 */
Java_org_coolreader_crengine_Engine_suspendLongOperationInternal(JNIEnv *,jclass)1081 JNIEXPORT void JNICALL Java_org_coolreader_crengine_Engine_suspendLongOperationInternal
1082 (JNIEnv *, jclass)
1083 {
1084 _timeoutControl.cancel();
1085 }
1086
1087
1088 #define BUTTON_BACKLIGHT_CONTROL_PATH "/sys/class/leds/button-backlight/brightness"
1089 /*
1090 * Class: org_coolreader_crengine_Engine
1091 * Method: setKeyBacklightInternal
1092 * Signature: (I)Z
1093 */
Java_org_coolreader_crengine_Engine_setKeyBacklightInternal(JNIEnv *,jclass,jint n)1094 JNIEXPORT jboolean JNICALL Java_org_coolreader_crengine_Engine_setKeyBacklightInternal
1095 (JNIEnv *, jclass, jint n)
1096 {
1097 FILE * f = fopen(BUTTON_BACKLIGHT_CONTROL_PATH, "wb");
1098 if (!f)
1099 return JNI_FALSE;
1100 fwrite(n ? "1" : "0", 1, 1, f);
1101 fclose(f);
1102 return JNI_TRUE;
1103 }
1104
1105 /*
1106 * Class: org_coolreader_crengine_Engine
1107 * Method: getDomVersionCurrent
1108 * Signature: ()I
1109 */
Java_org_coolreader_crengine_Engine_getDomVersionCurrent(JNIEnv *,jclass)1110 JNIEXPORT jint JNICALL Java_org_coolreader_crengine_Engine_getDomVersionCurrent
1111 (JNIEnv *, jclass)
1112 {
1113 return gDOMVersionCurrent;
1114 }
1115
1116 //=====================================================================
1117
1118 static JNINativeMethod sEngineMethods[] = {
1119 /* name, signature, funcPtr */
1120 {"initInternal", "([Ljava/lang/String;I)Z", (void*)Java_org_coolreader_crengine_Engine_initInternal},
1121 {"uninitInternal", "()V", (void*)Java_org_coolreader_crengine_Engine_uninitInternal},
1122 {"initDictionaries", "([Lorg/coolreader/crengine/Engine$HyphDict;)Z", (void*)Java_org_coolreader_crengine_Engine_initDictionaries},
1123 {"getFontFaceListInternal", "()[Ljava/lang/String;", (void*)Java_org_coolreader_crengine_Engine_getFontFaceListInternal},
1124 {"setCacheDirectoryInternal", "(Ljava/lang/String;I)Z", (void*)Java_org_coolreader_crengine_Engine_setCacheDirectoryInternal},
1125 {"scanBookPropertiesInternal", "(Lorg/coolreader/crengine/FileInfo;)Z", (void*)Java_org_coolreader_crengine_Engine_scanBookPropertiesInternal},
1126 {"updateFileCRC32Internal", "(Lorg/coolreader/crengine/FileInfo;)Z", (void*)Java_org_coolreader_crengine_Engine_updateFileCRC32Internal},
1127 {"getArchiveItemsInternal", "(Ljava/lang/String;)[Ljava/lang/String;", (void*)Java_org_coolreader_crengine_Engine_getArchiveItemsInternal},
1128 {"isLink", "(Ljava/lang/String;)Ljava/lang/String;", (void*)Java_org_coolreader_crengine_Engine_isLink},
1129 {"suspendLongOperationInternal", "()V", (void*)Java_org_coolreader_crengine_Engine_suspendLongOperationInternal},
1130 {"setKeyBacklightInternal", "(I)Z", (void*)Java_org_coolreader_crengine_Engine_setKeyBacklightInternal},
1131 {"scanBookCoverInternal", "(Ljava/lang/String;)[B", (void*)Java_org_coolreader_crengine_Engine_scanBookCoverInternal},
1132 {"drawBookCoverInternal", "(Landroid/graphics/Bitmap;[BLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V", (void*)Java_org_coolreader_crengine_Engine_drawBookCoverInternal},
1133 {"haveFcLangCodeInternal", "(Ljava/lang/String;)Z", (void*)Java_org_coolreader_crengine_Engine_haveFcLangCodeInternal},
1134 {"checkFontLanguageCompatibilityInternal", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)Java_org_coolreader_crengine_Engine_checkFontLanguageCompatibilityInternal},
1135 {"listFilesInternal", "(Ljava/io/File;)[Ljava/io/File;", (void*)Java_org_coolreader_crengine_Engine_listFilesInternal},
1136 {"getDomVersionCurrent", "()I", (void*)Java_org_coolreader_crengine_Engine_getDomVersionCurrent}
1137 };
1138
1139
1140 static JNINativeMethod sDocViewMethods[] = {
1141 /* name, signature, funcPtr */
1142 {"createInternal", "()V", (void*)Java_org_coolreader_crengine_DocView_createInternal},
1143 {"destroyInternal", "()V", (void*)Java_org_coolreader_crengine_DocView_destroyInternal},
1144 {"getPageImageInternal", "(Landroid/graphics/Bitmap;I)V", (void*)Java_org_coolreader_crengine_DocView_getPageImageInternal},
1145 {"loadDocumentInternal", "(Ljava/lang/String;)Z", (void*)Java_org_coolreader_crengine_DocView_loadDocumentInternal},
1146 {"loadDocumentFromMemoryInternal", "([BLjava/lang/String;)Z", (void*)Java_org_coolreader_crengine_DocView_loadDocumentFromMemoryInternal},
1147 {"getSettingsInternal", "()Ljava/util/Properties;", (void*)Java_org_coolreader_crengine_DocView_getSettingsInternal},
1148 {"getDocPropsInternal", "()Ljava/util/Properties;", (void*)Java_org_coolreader_crengine_DocView_getDocPropsInternal},
1149 {"applySettingsInternal", "(Ljava/util/Properties;)Z", (void*)Java_org_coolreader_crengine_DocView_applySettingsInternal},
1150 {"setStylesheetInternal", "(Ljava/lang/String;)V", (void*)Java_org_coolreader_crengine_DocView_setStylesheetInternal},
1151 {"resizeInternal", "(II)V", (void*)Java_org_coolreader_crengine_DocView_resizeInternal},
1152 {"doCommandInternal", "(II)Z", (void*)Java_org_coolreader_crengine_DocView_doCommandInternal},
1153 {"getCurrentPageBookmarkInternal", "()Lorg/coolreader/crengine/Bookmark;", (void*)Java_org_coolreader_crengine_DocView_getCurrentPageBookmarkInternal},
1154 {"goToPositionInternal", "(Ljava/lang/String;Z)Z", (void*)Java_org_coolreader_crengine_DocView_goToPositionInternal},
1155 {"getPositionPropsInternal", "(Ljava/lang/String;Z)Lorg/coolreader/crengine/PositionProperties;", (void*)Java_org_coolreader_crengine_DocView_getPositionPropsInternal},
1156 {"updateBookInfoInternal", "(Lorg/coolreader/crengine/BookInfo;)V", (void*)Java_org_coolreader_crengine_DocView_updateBookInfoInternal},
1157 {"getTOCInternal", "()Lorg/coolreader/crengine/TOCItem;", (void*)Java_org_coolreader_crengine_DocView_getTOCInternal},
1158 {"clearSelectionInternal", "()V", (void*)Java_org_coolreader_crengine_DocView_clearSelectionInternal},
1159 {"findTextInternal", "(Ljava/lang/String;III)Z", (void*)Java_org_coolreader_crengine_DocView_findTextInternal},
1160 {"setBatteryStateInternal", "(I)V", (void*)Java_org_coolreader_crengine_DocView_setBatteryStateInternal},
1161 {"getCoverPageDataInternal", "()[B", (void*)Java_org_coolreader_crengine_DocView_getCoverPageDataInternal},
1162 {"setPageBackgroundTextureInternal", "([BI)V", (void*)Java_org_coolreader_crengine_DocView_setPageBackgroundTextureInternal},
1163 {"updateSelectionInternal", "(Lorg/coolreader/crengine/Selection;)V", (void*)Java_org_coolreader_crengine_DocView_updateSelectionInternal},
1164 {"checkLinkInternal", "(III)Ljava/lang/String;", (void*)Java_org_coolreader_crengine_DocView_checkLinkInternal},
1165 {"goLinkInternal", "(Ljava/lang/String;)I", (void*)Java_org_coolreader_crengine_DocView_goLinkInternal},
1166 {"moveSelectionInternal", "(Lorg/coolreader/crengine/Selection;II)Z", (void*)Java_org_coolreader_crengine_DocView_moveSelectionInternal},
1167 {"swapToCacheInternal", "()I", (void*)Java_org_coolreader_crengine_DocView_swapToCacheInternal},
1168 {"checkImageInternal", "(IILorg/coolreader/crengine/ImageInfo;)Z", (void*)Java_org_coolreader_crengine_DocView_checkImageInternal},
1169 {"drawImageInternal", "(Landroid/graphics/Bitmap;ILorg/coolreader/crengine/ImageInfo;)Z", (void*)Java_org_coolreader_crengine_DocView_drawImageInternal},
1170 {"closeImageInternal", "()Z", (void*)Java_org_coolreader_crengine_DocView_closeImageInternal},
1171 {"hilightBookmarksInternal", "([Lorg/coolreader/crengine/Bookmark;)V", (void*)Java_org_coolreader_crengine_DocView_hilightBookmarksInternal},
1172 {"checkBookmarkInternal", "(IILorg/coolreader/crengine/Bookmark;)Z", (void*)Java_org_coolreader_crengine_DocView_checkBookmarkInternal},
1173 {"isRenderedInternal", "()Z", (void*)Java_org_coolreader_crengine_DocView_isRenderedInternal}
1174 };
1175
1176 /*
1177 * Register native JNI-callable methods.
1178 *
1179 * "className" looks like "java/lang/String".
1180 */
jniRegisterNativeMethods(JNIEnv * env,const char * className,const JNINativeMethod * gMethods,int numMethods)1181 static int jniRegisterNativeMethods(JNIEnv* env, const char* className,
1182 const JNINativeMethod* gMethods, int numMethods)
1183 {
1184 jclass clazz;
1185
1186 LOGV("Registering %s natives\n", className);
1187 clazz = env->FindClass(className);
1188 if (clazz == NULL) {
1189 LOGE("Native registration unable to find class '%s'\n", className);
1190 return -1;
1191 }
1192 if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
1193 LOGE("RegisterNatives failed for '%s'\n", className);
1194 return -1;
1195 }
1196 return 0;
1197 }
1198
1199
JNI_OnLoad(JavaVM * vm,void * reserved)1200 jint JNI_OnLoad(JavaVM* vm, void* reserved)
1201 {
1202 JNIEnv* env = NULL;
1203 jint res = -1;
1204
1205 #ifdef JNI_VERSION_1_6
1206 if (res==-1 && vm->GetEnv((void**) &env, JNI_VERSION_1_6) == JNI_OK) {
1207 LOGI("JNI_OnLoad: JNI_VERSION_1_6\n");
1208 res = JNI_VERSION_1_6;
1209 }
1210 #endif
1211 #ifdef JNI_VERSION_1_4
1212 if (res==-1 && vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) {
1213 LOGI("JNI_OnLoad: JNI_VERSION_1_4\n");
1214 res = JNI_VERSION_1_4;
1215 }
1216 #endif
1217 #ifdef JNI_VERSION_1_2
1218 if (res==-1 && vm->GetEnv((void**) &env, JNI_VERSION_1_2) == JNI_OK) {
1219 LOGI("JNI_OnLoad: JNI_VERSION_1_2\n");
1220 res = JNI_VERSION_1_2;
1221 }
1222 #endif
1223 if ( res==-1 )
1224 return res;
1225
1226 jniRegisterNativeMethods(env, "org/coolreader/crengine/Engine", sEngineMethods, sizeof(sEngineMethods)/sizeof(JNINativeMethod));
1227 jniRegisterNativeMethods(env, "org/coolreader/crengine/DocView", sDocViewMethods, sizeof(sDocViewMethods)/sizeof(JNINativeMethod));
1228 LOGI("JNI_OnLoad: native methods are registered!\n");
1229 return res;
1230 }
1231