mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 19:24:08 +00:00
540dda26ed
The replacement command: git grep -l 'qrcx://localhost' | xargs sed -i 's/qrcx:\/\/localhost/qrc:\/\//g' The qrcx:// URL scheme was introduced in 2009 or earlier - it is present in the first commit in GoldenDict's git history. Back then GoldenDict supported Qt versions earlier than 4.6, in which QWebSecurityOrigin::addLocalScheme() was introduced. Adding the qrc URL scheme as local obsoletes the qrcx URL scheme. GoldenDict does not compile against Qt versions earlier than 4.6, so there is no reason to use this custom URL scheme anymore. Co-authored-by: Igor Kushnir <igorkuo@gmail.com>
1951 lines
50 KiB
C++
1951 lines
50 KiB
C++
/* This file is (c) 2014 Abs62
|
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
|
|
|
#include "epwing_book.hh"
|
|
|
|
#include <QDir>
|
|
#include <QTextStream>
|
|
#include <QTextDocumentFragment>
|
|
#include <QHash>
|
|
#include "gddebug.hh"
|
|
#include "fsencoding.hh"
|
|
#include "audiolink.hh"
|
|
#include "wstring.hh"
|
|
#include "wstring_qt.hh"
|
|
#include "folding.hh"
|
|
#include "epwing_charmap.hh"
|
|
|
|
#if defined( Q_OS_WIN32 ) || defined( Q_OS_MAC )
|
|
#define _FILE_OFFSET_BITS 64
|
|
#endif
|
|
|
|
#include <eb/text.h>
|
|
#include <eb/appendix.h>
|
|
#include <eb/error.h>
|
|
#include <eb/binary.h>
|
|
#include <eb/font.h>
|
|
|
|
#define HitsBufferSize 512
|
|
|
|
namespace Epwing {
|
|
|
|
void initialize()
|
|
{
|
|
eb_initialize_library();
|
|
}
|
|
|
|
void finalize()
|
|
{
|
|
eb_finalize_library();
|
|
}
|
|
|
|
namespace Book {
|
|
|
|
#define HookFunc(name) \
|
|
EB_Error_Code name(EB_Book *, EB_Appendix *, void*, EB_Hook_Code, int, \
|
|
const unsigned int*)
|
|
|
|
HookFunc( hook_newline );
|
|
HookFunc( hook_iso8859_1 );
|
|
HookFunc( hook_narrow_jisx0208 );
|
|
HookFunc( hook_wide_jisx0208 );
|
|
HookFunc( hook_gb2312 );
|
|
HookFunc( hook_superscript );
|
|
HookFunc( hook_subscript );
|
|
HookFunc( hook_decoration );
|
|
HookFunc( hook_color_image );
|
|
HookFunc( hook_gray_image );
|
|
HookFunc( hook_mono_image );
|
|
HookFunc( hook_wave );
|
|
HookFunc( hook_mpeg );
|
|
HookFunc( hook_narrow_font );
|
|
HookFunc( hook_wide_font );
|
|
HookFunc( hook_reference );
|
|
|
|
const EB_Hook hooks[] = {
|
|
{ EB_HOOK_NEWLINE, hook_newline },
|
|
{ EB_HOOK_ISO8859_1, hook_iso8859_1 },
|
|
{ EB_HOOK_NARROW_JISX0208, hook_narrow_jisx0208 },
|
|
{ EB_HOOK_WIDE_JISX0208, hook_wide_jisx0208 },
|
|
{ EB_HOOK_GB2312, hook_gb2312 },
|
|
{ EB_HOOK_BEGIN_SUBSCRIPT, hook_subscript },
|
|
{ EB_HOOK_END_SUBSCRIPT, hook_subscript },
|
|
{ EB_HOOK_BEGIN_SUPERSCRIPT, hook_superscript },
|
|
{ EB_HOOK_END_SUPERSCRIPT, hook_superscript },
|
|
{ EB_HOOK_BEGIN_DECORATION, hook_decoration },
|
|
{ EB_HOOK_END_DECORATION, hook_decoration },
|
|
{ EB_HOOK_BEGIN_COLOR_BMP, hook_color_image },
|
|
{ EB_HOOK_BEGIN_COLOR_JPEG, hook_color_image },
|
|
{ EB_HOOK_END_COLOR_GRAPHIC, hook_color_image },
|
|
{ EB_HOOK_BEGIN_IN_COLOR_BMP, hook_color_image },
|
|
{ EB_HOOK_BEGIN_IN_COLOR_JPEG, hook_color_image },
|
|
{ EB_HOOK_END_IN_COLOR_GRAPHIC, hook_color_image },
|
|
{ EB_HOOK_BEGIN_MONO_GRAPHIC, hook_mono_image },
|
|
{ EB_HOOK_END_MONO_GRAPHIC, hook_mono_image },
|
|
{ EB_HOOK_BEGIN_WAVE, hook_wave },
|
|
{ EB_HOOK_END_WAVE, hook_wave },
|
|
{ EB_HOOK_BEGIN_MPEG, hook_mpeg },
|
|
{ EB_HOOK_END_MPEG, hook_mpeg },
|
|
{ EB_HOOK_NARROW_FONT, hook_narrow_font },
|
|
{ EB_HOOK_WIDE_FONT, hook_wide_font },
|
|
{ EB_HOOK_BEGIN_REFERENCE, hook_reference },
|
|
{ EB_HOOK_END_REFERENCE, hook_reference },
|
|
{ EB_HOOK_NULL, NULL }
|
|
};
|
|
|
|
const EB_Hook refHooks[] = {
|
|
{ EB_HOOK_BEGIN_REFERENCE, hook_reference },
|
|
{ EB_HOOK_END_REFERENCE, hook_reference },
|
|
{ EB_HOOK_NULL, NULL }
|
|
};
|
|
|
|
#define EUC_TO_ASCII_TABLE_START 0xa0
|
|
#define EUC_TO_ASCII_TABLE_END 0xff
|
|
|
|
// Tables from EB library
|
|
|
|
static const unsigned char euc_a1_to_ascii_table[] = {
|
|
0x00, 0x20, 0x00, 0x00, 0x2c, 0x2e, 0x00, 0x3a, /* 0xa0 */
|
|
0x3b, 0x3f, 0x21, 0x00, 0x00, 0x00, 0x60, 0x00, /* 0xa8 */
|
|
0x5e, 0x7e, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0 */
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2f, /* 0xb8 */
|
|
0x5c, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x27, /* 0xc0 */
|
|
0x00, 0x22, 0x28, 0x29, 0x00, 0x00, 0x5b, 0x5d, /* 0xc8 */
|
|
0x7b, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */
|
|
0x00, 0x00, 0x00, 0x00, 0x2b, 0x2d, 0x00, 0x00, /* 0xd8 */
|
|
0x00, 0x3d, 0x00, 0x3c, 0x3e, 0x00, 0x00, 0x00, /* 0xe0 */
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, /* 0xe8 */
|
|
0x24, 0x00, 0x00, 0x25, 0x23, 0x26, 0x2a, 0x40, /* 0xf0 */
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8 */
|
|
};
|
|
|
|
static const unsigned char euc_a3_to_ascii_table[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0 */
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8 */
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0xb0 */
|
|
0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8 */
|
|
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0xc0 */
|
|
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0xc8 */
|
|
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0xd0 */
|
|
0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8 */
|
|
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0xe0 */
|
|
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0xe8 */
|
|
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0xf0 */
|
|
0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8 */
|
|
};
|
|
|
|
// Hook functions
|
|
|
|
EB_Error_Code hook_newline( EB_Book * book, EB_Appendix *, void * ptr,
|
|
EB_Hook_Code, int, const unsigned int * )
|
|
{
|
|
EContainer * container = static_cast< EContainer * >( ptr );
|
|
|
|
if( container->textOnly )
|
|
eb_write_text_byte1( book, '\n' );
|
|
else
|
|
eb_write_text_string( book, "<br>" );
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_iso8859_1( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code, int, const unsigned int * argv )
|
|
{
|
|
EpwingBook * ebook = static_cast< EpwingBook * >( container );
|
|
if( ebook->codecISO() )
|
|
{
|
|
QByteArray b = ebook->codecISO()->toUnicode( (const char *)argv, 1 ).toUtf8();
|
|
eb_write_text( book, b.data(), b.size() );
|
|
}
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_narrow_jisx0208( EB_Book * book, EB_Appendix *,
|
|
void * container, EB_Hook_Code, int,
|
|
const unsigned int * argv )
|
|
{
|
|
if( *argv == 0xA1E3 )
|
|
eb_write_text_string( book, "<" );
|
|
else
|
|
if( *argv == 0xA1E4 )
|
|
eb_write_text_string( book, ">" );
|
|
else
|
|
if( *argv == 0xA1F5 )
|
|
eb_write_text_string( book, "&" );
|
|
else
|
|
{
|
|
unsigned char buf[ 2 ];
|
|
buf[ 0 ] = argv[ 0 ] >> 8;
|
|
buf[ 1 ] = argv[ 0 ] & 0xff;
|
|
int out_code = 0;
|
|
|
|
if( buf[ 0 ] == 0xA1 && buf[ 1 ] >= EUC_TO_ASCII_TABLE_START )
|
|
out_code = euc_a1_to_ascii_table[ buf[ 1 ] - EUC_TO_ASCII_TABLE_START ];
|
|
else
|
|
if( buf[ 0 ] == 0xA3 && buf[ 1 ] >= EUC_TO_ASCII_TABLE_START )
|
|
out_code = euc_a3_to_ascii_table[ buf[ 1 ] - EUC_TO_ASCII_TABLE_START ];
|
|
|
|
if( out_code == 0 )
|
|
{
|
|
EContainer * cont = static_cast< EContainer * >( container );
|
|
if( cont->book->codecEuc() )
|
|
{
|
|
QByteArray str = cont->book->codecEuc()->toUnicode( (const char *)buf, 2 ).toUtf8();
|
|
eb_write_text( book, str.data(), str.size() );
|
|
}
|
|
else
|
|
eb_write_text( book, (const char *)buf, 2 );
|
|
}
|
|
else
|
|
eb_write_text_byte1( book, out_code );
|
|
}
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_wide_jisx0208( EB_Book * book, EB_Appendix *, void * ptr,
|
|
EB_Hook_Code, int, const unsigned int * argv )
|
|
{
|
|
EpwingBook * ebook = static_cast< EContainer * >( ptr )->book;
|
|
|
|
char buf[2];
|
|
buf[1] = *argv & 0xFF;
|
|
buf[0] = ( *argv & 0xFF00 ) >> 8;
|
|
|
|
if( ebook->codecEuc() )
|
|
{
|
|
QByteArray b = ebook->codecEuc()->toUnicode( buf, 2 ).toUtf8();
|
|
eb_write_text( book, b.data(), b.size() );
|
|
}
|
|
else
|
|
eb_write_text_byte2( book, buf[ 0 ], buf[ 1 ] );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_gb2312( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code, int, const unsigned int * argv )
|
|
{
|
|
EpwingBook * ebook = static_cast< EContainer * >( container )->book;
|
|
|
|
char buf[2];
|
|
buf[1] = *argv & 0xFF;
|
|
buf[0] = ( *argv & 0xFF00 ) >> 8 ;
|
|
|
|
if( ebook->codecGB() )
|
|
{
|
|
QByteArray b = ebook->codecGB()->toUnicode( buf, 2 ).toUtf8();
|
|
eb_write_text( book, b.data(), b.size() );
|
|
}
|
|
else
|
|
eb_write_text_byte2( book, buf[ 0 ], buf[ 1 ] );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_subscript( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
if( code == EB_HOOK_BEGIN_SUBSCRIPT )
|
|
eb_write_text_string( book, cn->book->beginDecoration( EpwingBook::SUBSCRIPT ) );
|
|
|
|
if( code == EB_HOOK_END_SUBSCRIPT )
|
|
eb_write_text_string( book, cn->book->endDecoration( EpwingBook::SUBSCRIPT ) );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_superscript( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
if( code == EB_HOOK_BEGIN_SUPERSCRIPT )
|
|
eb_write_text_string( book, cn->book->beginDecoration( EpwingBook::SUPERSCRIPT ) );
|
|
|
|
if( code == EB_HOOK_END_SUPERSCRIPT )
|
|
eb_write_text_string( book, cn->book->endDecoration( EpwingBook::SUPERSCRIPT ) );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_decoration( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
if( code == EB_HOOK_BEGIN_DECORATION )
|
|
eb_write_text_string( book, cn->book->beginDecoration( argv[ 1 ] ) );
|
|
|
|
if( code == EB_HOOK_END_DECORATION )
|
|
eb_write_text_string( book, cn->book->endDecoration( argv[ 1 ] ) );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_color_image( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
QByteArray str = cn->book->handleColorImage( code, argv );
|
|
if( !str.isEmpty() )
|
|
eb_write_text( book, str.data(), str.size() );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_mono_image( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
QByteArray str = cn->book->handleMonoImage( code, argv );
|
|
if( !str.isEmpty() )
|
|
eb_write_text( book, str.data(), str.size() );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_wave( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
QByteArray str = cn->book->handleWave( code, argv );
|
|
if( !str.isEmpty() )
|
|
eb_write_text( book, str.data(), str.size() );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_mpeg( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
QByteArray str = cn->book->handleMpeg( code, argv );
|
|
if( !str.isEmpty() )
|
|
eb_write_text( book, str.data(), str.size() );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_narrow_font( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
QByteArray str = cn->book->handleNarrowFont( argv, cn->textOnly );
|
|
if( !str.isEmpty() )
|
|
eb_write_text( book, str.data(), str.size() );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_wide_font( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
QByteArray str = cn->book->handleWideFont( argv, cn->textOnly );
|
|
if( !str.isEmpty() )
|
|
eb_write_text( book, str.data(), str.size() );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
EB_Error_Code hook_reference( EB_Book * book, EB_Appendix *, void * container,
|
|
EB_Hook_Code code, int, const unsigned int * argv )
|
|
{
|
|
EContainer * cn = static_cast< EContainer * >( container );
|
|
|
|
if( cn->textOnly )
|
|
return EB_SUCCESS;
|
|
|
|
QByteArray str = cn->book->handleReference( code, argv );
|
|
if( !str.isEmpty() )
|
|
eb_write_text( book, str.data(), str.size() );
|
|
|
|
return EB_SUCCESS;
|
|
}
|
|
|
|
// EpwingBook class
|
|
|
|
EpwingBook::EpwingBook() :
|
|
currentSubBook( -1 )
|
|
{
|
|
codec_ISO = QTextCodec::codecForName( "ISO8859-1" );
|
|
codec_GB = QTextCodec::codecForName( "GB2312" );
|
|
codec_Euc = QTextCodec::codecForName("EUC-JP");
|
|
|
|
eb_initialize_book( &book );
|
|
eb_initialize_appendix( &appendix );
|
|
|
|
eb_initialize_hookset( &hookSet );
|
|
eb_set_hooks( &hookSet, hooks );
|
|
|
|
eb_initialize_hookset( &refHookSet );
|
|
eb_set_hooks( &refHookSet, refHooks );
|
|
}
|
|
|
|
EpwingBook::~EpwingBook()
|
|
{
|
|
eb_finalize_hookset( &hookSet );
|
|
eb_finalize_appendix( &appendix );
|
|
eb_finalize_book( &book );
|
|
}
|
|
|
|
void EpwingBook::setErrorString( QString const & func, EB_Error_Code code )
|
|
{
|
|
error_string = QString( "EB \"%1\" function error: %2 (%3)" )
|
|
.arg( func )
|
|
.arg( QTextCodec::codecForLocale()->toUnicode( eb_error_string( code ) ) )
|
|
.arg( QTextCodec::codecForLocale()->toUnicode( eb_error_message( code ) ) );
|
|
|
|
if( currentPosition.page != 0 )
|
|
error_string += QString( " on page %1, offset %2" ).arg( QString::number( currentPosition.page ) )
|
|
.arg( QString::number( currentPosition.offset ) );
|
|
}
|
|
|
|
void EpwingBook::collectFilenames( QString const & directory, vector< string > & files )
|
|
{
|
|
QDir dir( directory );
|
|
QString catName;
|
|
catName += QDir::separator();
|
|
catName += "catalogs";
|
|
|
|
QFileInfoList entries = dir.entryInfoList( QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot,
|
|
QDir::Name | QDir::DirsLast );
|
|
|
|
for( QFileInfoList::const_iterator i = entries.constBegin();
|
|
i != entries.constEnd(); ++i )
|
|
{
|
|
QString fullName = QDir::toNativeSeparators( i->filePath() );
|
|
|
|
if( i->isDir() )
|
|
collectFilenames( fullName, files );
|
|
else
|
|
files.push_back( FsEncoding::encode( fullName ) );
|
|
}
|
|
}
|
|
|
|
int EpwingBook::setBook( string const & directory )
|
|
{
|
|
error_string.clear();
|
|
|
|
if( directory.empty() )
|
|
throw exEpwing( "No such directory" );
|
|
|
|
currentPosition.page = 0;
|
|
|
|
indexHeadwordsPosition.page = 0;
|
|
indexHeadwordsPosition.offset = 0;
|
|
|
|
currentSubBook = -1;
|
|
|
|
EB_Error_Code ret = eb_bind( &book, directory.c_str() );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_bind", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
return -1;
|
|
}
|
|
|
|
ret = eb_bind_appendix( &appendix, directory.c_str() );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_bind_appendix", ret );
|
|
}
|
|
|
|
ret = eb_subbook_list( &book, subBookList, &subBookCount );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_subbook_list", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
ret = eb_appendix_subbook_list( &appendix, subAppendixList, &subAppendixCount );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_appendix_subbook_list", ret );
|
|
}
|
|
|
|
if( !codec_Euc
|
|
|| ( book.character_code == EB_CHARCODE_ISO8859_1 && !codec_ISO )
|
|
|| ( book.character_code == EB_CHARCODE_JISX0208_GB2312 && !codec_GB ) )
|
|
throw exEpwing( "No required codec to decode dictionary" );
|
|
|
|
rootDir = FsEncoding::decode( directory.c_str() );
|
|
|
|
return subBookCount;
|
|
}
|
|
|
|
bool EpwingBook::setSubBook( int book_nom )
|
|
{
|
|
error_string.clear();
|
|
|
|
customFontsMap.clear();
|
|
|
|
currentPosition.page = 0;
|
|
|
|
if( book_nom < 0 || book_nom >= subBookCount )
|
|
throw exEpwing( "Invalid subbook number" );
|
|
|
|
if( currentSubBook == book_nom )
|
|
return true;
|
|
|
|
EB_Error_Code ret = eb_set_subbook( &book, subBookList[ book_nom ] );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_set_subbook", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
currentSubBook = book_nom;
|
|
|
|
if( book_nom < subAppendixCount )
|
|
{
|
|
ret = eb_set_appendix_subbook( &appendix, subAppendixList[ book_nom ] );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_set_appendix_subbook", ret );
|
|
}
|
|
}
|
|
|
|
if( eb_have_font( &book, EB_FONT_16 ) )
|
|
{
|
|
ret = eb_set_font( &book, EB_FONT_16 );
|
|
if( ret != EB_SUCCESS )
|
|
setErrorString( "eb_set_font", ret );
|
|
}
|
|
|
|
// Load fonts list
|
|
|
|
QString fileName = rootDir + QDir::separator()
|
|
+ "afonts_" + QString::number( book_nom );
|
|
|
|
QFile f( fileName );
|
|
if( f.open( QFile::ReadOnly | QFile::Text ) )
|
|
{
|
|
QTextStream ts( &f );
|
|
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
|
|
ts.setCodec( "UTF-8" );
|
|
#else
|
|
ts.setEncoding(QStringConverter::Utf8);
|
|
#endif
|
|
|
|
QString line = ts.readLine();
|
|
while( !line.isEmpty() )
|
|
{
|
|
QStringList list = line.remove( '\n' ).split( ' ', Qt::SkipEmptyParts );
|
|
if( list.count() == 2 )
|
|
customFontsMap[ list[ 0 ] ] = list[ 1 ];
|
|
line = ts.readLine();
|
|
}
|
|
|
|
f.close();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void EpwingBook::setCacheDirectory( QString const & cacheDir )
|
|
{
|
|
mainCacheDir = cacheDir;
|
|
cacheImagesDir.clear();
|
|
cacheSoundsDir.clear();
|
|
cacheMoviesDir.clear();
|
|
cacheFontsDir.clear();
|
|
|
|
imageCacheList.clear();
|
|
soundsCacheList.clear();
|
|
moviesCacheList.clear();
|
|
fontsCacheList.clear();
|
|
}
|
|
|
|
QString EpwingBook::createCacheDir( QString const & dirName )
|
|
{
|
|
QDir dir;
|
|
QFileInfo info( mainCacheDir );
|
|
if( !info.exists() || !info.isDir() )
|
|
{
|
|
if( !dir.mkdir( mainCacheDir ) )
|
|
{
|
|
gdWarning( "Epwing: can't create cache directory \"%s\"", mainCacheDir.toUtf8().data() );
|
|
return QString();
|
|
}
|
|
}
|
|
|
|
QString cacheDir = mainCacheDir + QDir::separator() + dirName;
|
|
info = QFileInfo( cacheDir );
|
|
if( !info.exists() || !info.isDir() )
|
|
{
|
|
if( !dir.mkdir( cacheDir ) )
|
|
{
|
|
gdWarning( "Epwing: can't create cache directory \"%s\"", cacheDir.toUtf8().data() );
|
|
return QString();
|
|
}
|
|
}
|
|
return cacheDir;
|
|
}
|
|
|
|
QString EpwingBook::getCurrentSubBookDirectory()
|
|
{
|
|
error_string.clear();
|
|
|
|
if( currentSubBook < 0 || currentSubBook >= subBookCount )
|
|
{
|
|
setErrorString( "eb_subbook_directory2", EB_ERR_NO_SUCH_BOOK );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
char buffer[ EB_MAX_PATH_LENGTH + 1 ];
|
|
|
|
EB_Error_Code ret = eb_subbook_directory2( &book, subBookList[ currentSubBook ], buffer );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_subbook_directory2", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
return QString::fromLocal8Bit( buffer );
|
|
}
|
|
|
|
QString EpwingBook::makeFName( QString const & ext, int page, int offset ) const
|
|
{
|
|
QString name = QString::number( page )
|
|
+ "x"
|
|
+ QString::number( offset )
|
|
+ "."
|
|
+ ext;
|
|
return name;
|
|
}
|
|
|
|
QString EpwingBook::title()
|
|
{
|
|
char buf[ EB_MAX_TITLE_LENGTH + 1 ];
|
|
error_string.clear();
|
|
|
|
EB_Error_Code ret = eb_subbook_title( &book, buf );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_subbook_title", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
buf[ EB_MAX_TITLE_LENGTH ] = 0;
|
|
if( codec_Euc )
|
|
return codec_Euc->toUnicode( buf );
|
|
|
|
return QString();
|
|
}
|
|
|
|
QString EpwingBook::copyright()
|
|
{
|
|
error_string.clear();
|
|
|
|
if( !eb_have_copyright( &book ) )
|
|
return QString();
|
|
|
|
EB_Position position;
|
|
EB_Error_Code ret = eb_copyright( &book, &position );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_copyright", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
currentPosition = position;
|
|
|
|
return getText( position.page, position.offset, true );
|
|
}
|
|
|
|
QString EpwingBook::getText( int page, int offset, bool text_only )
|
|
{
|
|
error_string.clear();
|
|
|
|
EB_Position pos;
|
|
pos.page = page;
|
|
pos.offset = offset;
|
|
currentPosition = pos;
|
|
|
|
EB_Error_Code ret = eb_seek_text(&book, &pos);
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_seek_text", ret );
|
|
currentPosition.page = 0;
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
QByteArray buf;
|
|
char buffer[ TextBufferSize + 1 ];
|
|
ssize_t buffer_length;
|
|
|
|
EContainer container( this, text_only );
|
|
|
|
prepareToRead();
|
|
|
|
for( ; ; )
|
|
{
|
|
ret = eb_read_text( &book, &appendix, &hookSet, &container,
|
|
TextBufferSize, buffer, &buffer_length );
|
|
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_text", ret );
|
|
break;
|
|
}
|
|
|
|
buf += QByteArray( buffer, buffer_length );
|
|
|
|
if( eb_is_text_stopped( &book ) )
|
|
break;
|
|
|
|
if( buf.length() > TextSizeLimit )
|
|
{
|
|
error_string = "Data too large";
|
|
currentPosition.page = 0;
|
|
return QString();
|
|
}
|
|
}
|
|
|
|
QString text = QString::fromUtf8( buf.data(), buf.size() ).trimmed();
|
|
finalizeText( text);
|
|
return text;
|
|
}
|
|
|
|
void EpwingBook::getReferencesFromText( int page, int offset )
|
|
{
|
|
error_string.clear();
|
|
|
|
EB_Position pos;
|
|
pos.page = page;
|
|
pos.offset = offset;
|
|
|
|
currentPosition = pos;
|
|
|
|
EB_Error_Code ret = eb_seek_text(&book, &pos);
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_seek_text", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
char buffer[ TextBufferSize + 1 ];
|
|
ssize_t buffer_length;
|
|
|
|
EContainer container( this, false );
|
|
|
|
prepareToRead();
|
|
|
|
for( ; ; )
|
|
{
|
|
ret = eb_read_text( &book, &appendix, &refHookSet, &container,
|
|
TextBufferSize, buffer, &buffer_length );
|
|
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_text", ret );
|
|
break;
|
|
}
|
|
|
|
if( eb_is_text_stopped( &book ) )
|
|
break;
|
|
}
|
|
|
|
for( int x = 0; x < refPages.size(); x++ )
|
|
{
|
|
LinksQueue.push_back( EWPos( refPages[ x ], refOffsets[ x ] ) );
|
|
}
|
|
}
|
|
|
|
EB_Error_Code EpwingBook::forwardText( EB_Position & startPos )
|
|
{
|
|
EB_Error_Code ret = eb_seek_text( &book, &startPos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_seek_text", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
ret = eb_forward_text( &book, &appendix );
|
|
while( ret == EB_ERR_END_OF_CONTENT )
|
|
{
|
|
ret = eb_tell_text( &book, &startPos );
|
|
if( ret != EB_SUCCESS )
|
|
break;
|
|
|
|
if( startPos.page >= book.subbook_current->text.end_page )
|
|
return EB_ERR_END_OF_CONTENT;
|
|
|
|
startPos.offset += 2;
|
|
currentPosition = startPos;
|
|
|
|
ret = eb_seek_text( &book, &startPos );
|
|
|
|
if( ret == EB_SUCCESS )
|
|
ret = eb_forward_text( &book, &appendix );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void EpwingBook::getFirstHeadword( EpwingHeadword & head )
|
|
{
|
|
error_string.clear();
|
|
|
|
EB_Position pos;
|
|
|
|
EB_Error_Code ret = eb_text( &book, &pos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_text", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
ret = forwardText( pos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "forwardText", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
eb_backward_text( &book, &appendix );
|
|
|
|
ret = eb_tell_text( &book, &pos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_tell_text", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
currentPosition = pos;
|
|
indexHeadwordsPosition = pos;
|
|
|
|
head.page = pos.page;
|
|
head.offset = pos.offset;
|
|
|
|
if( !readHeadword( pos, head.headword, true ) )
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
|
|
fixHeadword( head.headword );
|
|
|
|
EWPos epos( pos.page, pos.offset );
|
|
allHeadwordPositions[ ((uint64_t)pos.page)<<32|(pos.offset) ] =true;
|
|
}
|
|
|
|
bool EpwingBook::getNextHeadword( EpwingHeadword & head )
|
|
{
|
|
EB_Position pos;
|
|
|
|
|
|
// No queued positions - forward to next article
|
|
|
|
error_string.clear();
|
|
|
|
pos = indexHeadwordsPosition;
|
|
|
|
for( ; ; )
|
|
{
|
|
EB_Error_Code ret = forwardText( pos );
|
|
indexHeadwordsPosition = pos;
|
|
|
|
if( ret == EB_ERR_END_OF_CONTENT )
|
|
return false;
|
|
else
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_forward_text", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
ret = eb_tell_text( &book, &pos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_tell_text", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
indexHeadwordsPosition = pos;
|
|
|
|
|
|
|
|
head.page = pos.page;
|
|
head.offset = pos.offset;
|
|
|
|
if( !readHeadword( pos, head.headword, true ) )
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
|
|
if( head.headword.isEmpty() )
|
|
continue;
|
|
|
|
fixHeadword( head.headword );
|
|
|
|
try
|
|
{
|
|
getReferencesFromText( pos.page, pos.offset);
|
|
}
|
|
catch( std::exception & )
|
|
{
|
|
}
|
|
|
|
if( !allHeadwordPositions.contains( ((uint64_t)pos.page) << 32 | ( pos.offset ) ) )
|
|
{
|
|
allHeadwordPositions[ ((uint64_t)pos.page) << 32 | ( pos.offset ) ] = true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool EpwingBook::processRef( EpwingHeadword & head)
|
|
{
|
|
EB_Position pos;
|
|
|
|
QRegularExpression badLinks( "#(v|n)\\d", QRegularExpression::UseUnicodePropertiesOption );
|
|
while( !LinksQueue.isEmpty() )
|
|
{
|
|
EWPos epos = LinksQueue.last();
|
|
LinksQueue.pop_back();
|
|
|
|
pos.page = epos.first;
|
|
pos.offset = epos.second;
|
|
|
|
if( readHeadword( pos, head.headword, true ) )
|
|
{
|
|
if( head.headword.isEmpty() || head.headword.contains( badLinks ) )
|
|
continue;
|
|
|
|
fixHeadword( head.headword );
|
|
|
|
head.page = pos.page;
|
|
head.offset = pos.offset;
|
|
auto key = ( (uint64_t)pos.page ) << 32 | ( pos.offset );
|
|
if( !allRefPositions.contains( key ) )
|
|
{
|
|
// fixed the reference headword ,to avoid the headword collision with other entry .
|
|
//if(!allHeadwordPositions.contains(key))
|
|
head.headword = QString( "r%1At%2" ).arg( pos.page ).arg( pos.offset );
|
|
|
|
allRefPositions[ key ] = true;
|
|
|
|
try
|
|
{
|
|
getReferencesFromText( pos.page, pos.offset);
|
|
}
|
|
catch( std::exception & )
|
|
{
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool EpwingBook::readHeadword( EB_Position const& pos,
|
|
QString & headword,
|
|
bool text_only )
|
|
{
|
|
EContainer container( this, text_only );
|
|
ssize_t head_length;
|
|
|
|
EB_Position newPos = pos;
|
|
|
|
EB_Error_Code ret = eb_seek_text( &book, &newPos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_seek_text", ret );
|
|
return false;
|
|
}
|
|
|
|
char buffer[ TextBufferSize + 1 ];
|
|
|
|
ret = eb_read_heading( &book, &appendix, &hookSet, &container,
|
|
TextBufferSize, buffer, &head_length );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_heading", ret );
|
|
return false;
|
|
}
|
|
|
|
headword = QString::fromUtf8( buffer, head_length );
|
|
return true;
|
|
}
|
|
|
|
bool EpwingBook::isHeadwordCorrect( QString const & headword )
|
|
{
|
|
QByteArray buf, buf2;
|
|
EB_Hit hits[ 2 ];
|
|
int hit_count;
|
|
EB_Error_Code ret;
|
|
|
|
if( headword.isEmpty() )
|
|
return false;
|
|
|
|
if( book.character_code == EB_CHARCODE_ISO8859_1 && codec_ISO )
|
|
buf = codec_ISO->fromUnicode( headword );
|
|
else
|
|
if( ( book.character_code == EB_CHARCODE_JISX0208 || book.character_code == EB_CHARCODE_JISX0208_GB2312 )
|
|
&& codec_Euc )
|
|
buf = codec_Euc->fromUnicode( headword );
|
|
|
|
if( book.character_code == EB_CHARCODE_JISX0208_GB2312 && codec_GB )
|
|
buf2 = codec_GB->fromUnicode( headword );
|
|
|
|
if( !buf.isEmpty() && eb_search_exactword( &book, buf.data() ) == EB_SUCCESS )
|
|
{
|
|
ret = eb_hit_list( &book, 2, hits, &hit_count );
|
|
if( ret == EB_SUCCESS && hit_count > 0 )
|
|
return true;
|
|
}
|
|
|
|
if( !buf2.isEmpty() && eb_search_exactword( &book, buf2.data() ) == EB_SUCCESS )
|
|
{
|
|
ret = eb_hit_list( &book, 2, hits, &hit_count );
|
|
if( ret == EB_SUCCESS && hit_count > 0 )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void EpwingBook::fixHeadword( QString & headword )
|
|
{
|
|
if(headword.isEmpty() )
|
|
return;
|
|
|
|
headword.remove( QChar( 0x30FB ) ); // Used in Japan transcription
|
|
|
|
//replace any unicode Number ,Symbol ,Punctuation ,Mark character to whitespace
|
|
headword.replace( QRegularExpression( R"([\p{N}\p{S}\p{P}\p{M}])" ), " " );
|
|
|
|
//if( isHeadwordCorrect( headword) )
|
|
// return;
|
|
|
|
QString fixed = headword;
|
|
QRegularExpression leadingSlashRx( "/[^/]+/" );
|
|
fixed.remove(leadingSlashRx );
|
|
|
|
//if( isHeadwordCorrect( fixed ) )
|
|
//{
|
|
// headword = fixed;
|
|
// return;
|
|
//}
|
|
|
|
gd::wstring folded = Folding::applyPunctOnly( gd::toWString( fixed ) );
|
|
//fixed = gd::toQString( folded );
|
|
|
|
//if( isHeadwordCorrect( fixed ) )
|
|
//{
|
|
// headword = fixed;
|
|
// return;
|
|
//}
|
|
|
|
folded = Folding::applyDiacriticsOnly( folded );
|
|
fixed = gd::toQString( folded );
|
|
|
|
//if( isHeadwordCorrect( fixed ) )
|
|
//{
|
|
// headword = fixed;
|
|
// return;
|
|
//}
|
|
|
|
//folded = Folding::applyWhitespaceOnly( folded );
|
|
//fixed = gd::toQString( folded );
|
|
|
|
//if( isHeadwordCorrect( fixed ) )
|
|
// headword = fixed;
|
|
|
|
headword = fixed;
|
|
}
|
|
|
|
void EpwingBook::getArticle( QString & headword, QString & articleText,
|
|
int page, int offset, bool text_only)
|
|
{
|
|
error_string.clear();
|
|
char buffer[ TextBufferSize + 1 ];
|
|
|
|
EB_Position pos;
|
|
pos.page = page;
|
|
pos.offset = offset;
|
|
|
|
currentPosition = pos;
|
|
|
|
EB_Error_Code ret = eb_seek_text( &book, &pos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_seek_text", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
EContainer container( this, text_only );
|
|
ssize_t length;
|
|
|
|
prepareToRead();
|
|
|
|
ret = eb_read_heading( &book, &appendix, &hookSet, &container,
|
|
TextBufferSize, buffer, &length );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_heading", ret );
|
|
throw exEbLibrary( error_string.toUtf8().data() );
|
|
}
|
|
|
|
headword = QString::fromUtf8( buffer, length );
|
|
finalizeText( headword);
|
|
|
|
if( text_only )
|
|
fixHeadword( headword );
|
|
|
|
articleText = getText( pos.page, pos.offset, text_only);
|
|
}
|
|
|
|
const char * EpwingBook::beginDecoration( unsigned int code )
|
|
{
|
|
const char * str = "";
|
|
|
|
code = normalizeDecorationCode( code );
|
|
|
|
switch( code )
|
|
{
|
|
case ITALIC: str = "<i>";
|
|
break;
|
|
case BOLD: str = "<b>";
|
|
break;
|
|
case EMPHASIS: str = "<em>";
|
|
break;
|
|
case SUBSCRIPT: str = "<sub>";
|
|
break;
|
|
case SUPERSCRIPT: str = "<sup>";
|
|
break;
|
|
default: gdWarning( "Epwing: Unknown decoration code %i", code );
|
|
code = UNKNOWN;
|
|
break;
|
|
}
|
|
decorationStack.push( code );
|
|
return str;
|
|
}
|
|
|
|
const char * EpwingBook::endDecoration( unsigned int code )
|
|
{
|
|
const char * str = "";
|
|
|
|
code = normalizeDecorationCode( code );
|
|
|
|
if( code != ITALIC && code != BOLD && code != EMPHASIS
|
|
&& code != SUBSCRIPT && code != SUPERSCRIPT )
|
|
code = UNKNOWN;
|
|
|
|
unsigned int storedCode = UNKNOWN;
|
|
if( !decorationStack.isEmpty() )
|
|
storedCode = decorationStack.pop();
|
|
|
|
if( storedCode != code )
|
|
{
|
|
gdWarning( "Epwing: tags mismatch detected" );
|
|
if( storedCode == UNKNOWN )
|
|
storedCode = code;
|
|
}
|
|
|
|
switch( storedCode )
|
|
{
|
|
case ITALIC: str = "</i>";
|
|
break;
|
|
case BOLD: str = "</b>";
|
|
break;
|
|
case EMPHASIS: str = "</em>";
|
|
break;
|
|
case SUBSCRIPT: str = "</sub>";
|
|
break;
|
|
case SUPERSCRIPT: str = "</sup>";
|
|
break;
|
|
case UNKNOWN: break;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
unsigned int EpwingBook::normalizeDecorationCode( unsigned int code )
|
|
{
|
|
// Some non-standard codes
|
|
switch( code )
|
|
{
|
|
case 0x1101: return BOLD;
|
|
case 0x1103: return ITALIC;
|
|
}
|
|
return code;
|
|
}
|
|
|
|
void EpwingBook::finalizeText( QString & text )
|
|
{
|
|
// Close unclosed tags
|
|
while( !decorationStack.isEmpty() )
|
|
{
|
|
unsigned int code = decorationStack.pop();
|
|
switch( code )
|
|
{
|
|
case ITALIC: text += "</i>";
|
|
break;
|
|
case BOLD: text += "</b>";
|
|
break;
|
|
case EMPHASIS: text += "</em>";
|
|
break;
|
|
case SUBSCRIPT: text += "</sub>";
|
|
break;
|
|
case SUPERSCRIPT: text += "</sup>";
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Replace references
|
|
|
|
int pos = 0;
|
|
QString reg1( "<R%1>");
|
|
QString reg2( "</R%1>");
|
|
|
|
EContainer cont( this, true );
|
|
|
|
char buf[ TextBufferSize + 1 ];
|
|
|
|
for( int x = 0; x < refCloseCount; x++ )
|
|
{
|
|
auto tag1=reg1.arg(x);
|
|
auto tag2=reg2.arg(x);
|
|
pos = text.indexOf( tag1, pos );
|
|
if( pos < 0 )
|
|
continue;
|
|
|
|
EB_Position ebpos;
|
|
ebpos.page = refPages[ x ];
|
|
ebpos.offset = refOffsets[ x ];
|
|
|
|
QUrl url;
|
|
url.setScheme( "gdlookup" );
|
|
url.setHost( "localhost" );
|
|
|
|
// Read headword
|
|
|
|
eb_seek_text( &book, &ebpos );
|
|
|
|
ssize_t length;
|
|
EB_Error_Code ret = eb_read_heading( &book, &appendix, &hookSet, &cont,
|
|
TextBufferSize, buf, &length );
|
|
if( ret == EB_SUCCESS )
|
|
{
|
|
QString headword = QString::fromUtf8( buf, length );
|
|
fixHeadword( headword );
|
|
url.setPath( Utils::Url::ensureLeadingSlash( QString( "r%1At%2" ).arg( ebpos.page ).arg(ebpos.offset) ) );
|
|
}
|
|
|
|
QString link = "<a href=\"" + url.toEncoded() + "\">";
|
|
|
|
text.replace( tag1, link );
|
|
|
|
pos = text.indexOf( tag2, pos );
|
|
if( pos < 0 )
|
|
continue;
|
|
|
|
text.replace( tag2, "</a>" );
|
|
}
|
|
}
|
|
|
|
void EpwingBook::prepareToRead()
|
|
{
|
|
refPages.clear();
|
|
refOffsets.clear();
|
|
refOpenCount = refCloseCount = 0;
|
|
}
|
|
|
|
QByteArray EpwingBook::handleColorImage( EB_Hook_Code code,
|
|
const unsigned int * argv )
|
|
{
|
|
QString name, fullName;
|
|
EB_Position pos;
|
|
|
|
if( code == EB_HOOK_END_COLOR_GRAPHIC
|
|
|| code == EB_HOOK_END_IN_COLOR_GRAPHIC )
|
|
return QByteArray();
|
|
|
|
pos.page = argv[ 2 ];
|
|
pos.offset = argv[ 3 ];
|
|
|
|
EB_Error_Code ret = eb_set_binary_color_graphic( &book, & pos );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_set_binary_color_graphic", ret );
|
|
gdWarning( "Epwing image retrieve error: %s",
|
|
error_string.toUtf8().data() );
|
|
return QByteArray();
|
|
}
|
|
|
|
if( cacheImagesDir.isEmpty() )
|
|
cacheImagesDir = createCacheDir( "images" );
|
|
|
|
if( code == EB_HOOK_BEGIN_COLOR_BMP
|
|
|| code == EB_HOOK_BEGIN_IN_COLOR_BMP )
|
|
name = makeFName( "bmp", pos.page, pos.offset );
|
|
else
|
|
if( code == EB_HOOK_BEGIN_COLOR_JPEG
|
|
|| code == EB_HOOK_BEGIN_IN_COLOR_JPEG )
|
|
name = makeFName( "jpg", pos.page, pos.offset );
|
|
|
|
if( !cacheImagesDir.isEmpty() )
|
|
fullName = cacheImagesDir + QDir::separator() + name;
|
|
|
|
QUrl url;
|
|
url.setScheme( "bres" );
|
|
url.setHost( dictID );
|
|
url.setPath( Utils::Url::ensureLeadingSlash( name ) );
|
|
QByteArray urlStr = R"(<p class="epwing_image"><img src=")" + url.toEncoded()
|
|
+ "\" alt=\"" + name.toUtf8() + "\"></p>";
|
|
|
|
if( imageCacheList.contains( name, Qt::CaseSensitive ) )
|
|
{
|
|
// We already have this image in cache
|
|
return urlStr;
|
|
}
|
|
|
|
if( !fullName.isEmpty() )
|
|
{
|
|
QFile f( fullName );
|
|
if( f.open( QFile::WriteOnly ) )
|
|
{
|
|
QByteArray buffer;
|
|
buffer.resize( BinaryBufferSize );
|
|
ssize_t length;
|
|
|
|
for( ; ; )
|
|
{
|
|
ret = eb_read_binary( &book, BinaryBufferSize,
|
|
buffer.data(), &length );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_binary", ret );
|
|
gdWarning( "Epwing image retrieve error: %s",
|
|
error_string.toUtf8().data() );
|
|
break;
|
|
}
|
|
|
|
f.write( buffer.data(), length );
|
|
|
|
if( length < BinaryBufferSize )
|
|
break;
|
|
}
|
|
f.close();
|
|
|
|
imageCacheList.append( name );
|
|
}
|
|
}
|
|
|
|
return urlStr;
|
|
}
|
|
|
|
QByteArray EpwingBook::handleMonoImage( EB_Hook_Code code,
|
|
const unsigned int * argv )
|
|
{
|
|
QString name, fullName;
|
|
EB_Position pos;
|
|
|
|
if( code == EB_HOOK_BEGIN_MONO_GRAPHIC )
|
|
{
|
|
monoHeight = argv[ 2 ];
|
|
monoWidth = argv[ 3 ];
|
|
return QByteArray();
|
|
}
|
|
|
|
// Handle EB_HOOK_END_MONO_GRAPHIC hook
|
|
|
|
pos.page = argv[ 1 ];
|
|
pos.offset = argv[ 2 ];
|
|
|
|
EB_Error_Code ret = eb_set_binary_mono_graphic( &book, &pos, monoWidth, monoHeight );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_set_binary_mono_graphic", ret );
|
|
gdWarning( "Epwing image retrieve error: %s",
|
|
error_string.toUtf8().data() );
|
|
return QByteArray();
|
|
}
|
|
|
|
if( cacheImagesDir.isEmpty() )
|
|
cacheImagesDir = createCacheDir( "images" );
|
|
|
|
name = makeFName( "bmp", pos.page, pos.offset );
|
|
|
|
if( !cacheImagesDir.isEmpty() )
|
|
fullName = cacheImagesDir + QDir::separator() + name;
|
|
|
|
QUrl url;
|
|
url.setScheme( "bres" );
|
|
url.setHost( dictID );
|
|
url.setPath( Utils::Url::ensureLeadingSlash( name ) );
|
|
QByteArray urlStr = R"(<span class="epwing_image"><img src=")" + url.toEncoded()
|
|
+ "\" alt=\"" + name.toUtf8() + "\"/></span>";
|
|
|
|
if( imageCacheList.contains( name, Qt::CaseSensitive ) )
|
|
{
|
|
// We already have this image in cache
|
|
return urlStr;
|
|
}
|
|
|
|
if( !fullName.isEmpty() )
|
|
{
|
|
QFile f( fullName );
|
|
if( f.open( QFile::WriteOnly | QFile::Truncate ) )
|
|
{
|
|
QByteArray buffer;
|
|
buffer.resize( BinaryBufferSize );
|
|
ssize_t length;
|
|
|
|
for( ; ; )
|
|
{
|
|
ret = eb_read_binary( &book, BinaryBufferSize,
|
|
buffer.data(), &length );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_binary", ret );
|
|
gdWarning( "Epwing image retrieve error: %s",
|
|
error_string.toUtf8().data() );
|
|
break;
|
|
}
|
|
|
|
f.write( buffer.data(), length );
|
|
|
|
if( length < BinaryBufferSize )
|
|
break;
|
|
}
|
|
f.close();
|
|
|
|
imageCacheList.append( name );
|
|
}
|
|
}
|
|
|
|
return urlStr;
|
|
}
|
|
|
|
QByteArray EpwingBook::handleWave( EB_Hook_Code code, const unsigned int * argv )
|
|
{
|
|
|
|
if( code == EB_HOOK_END_WAVE )
|
|
return QByteArray( R"(<img src="qrc:///icons/playsound.png" border="0" align="absmiddle" alt="Play"/></a></span>)" );
|
|
|
|
// Handle EB_HOOK_BEGIN_WAVE
|
|
|
|
EB_Position spos, epos;
|
|
spos.page = argv[ 2 ];
|
|
spos.offset = argv[ 3 ];
|
|
epos.page = argv[ 4 ];
|
|
epos.offset = argv[ 5 ];
|
|
|
|
eb_set_binary_wave( &book, &spos, &epos );
|
|
|
|
if( cacheSoundsDir.isEmpty() )
|
|
cacheSoundsDir = createCacheDir( "sounds" );
|
|
|
|
QString name = makeFName( "wav", spos.page, spos.offset );
|
|
QString fullName;
|
|
|
|
if( !cacheSoundsDir.isEmpty() )
|
|
fullName = cacheSoundsDir + QDir::separator() + name;
|
|
|
|
QUrl url;
|
|
url.setScheme( "gdau" );
|
|
url.setHost( dictID );
|
|
url.setPath( Utils::Url::ensureLeadingSlash( name ) );
|
|
|
|
string ref = string( "\"" )+ url.toEncoded().data() + "\"";
|
|
QByteArray result = addAudioLink( ref , dictID.toUtf8().data() ).c_str();
|
|
|
|
result += QByteArray( "<span class=\"epwing_wav\"><a href=" ) + ref.c_str() + ">";
|
|
|
|
if( soundsCacheList.contains( name, Qt::CaseSensitive ) )
|
|
{
|
|
// We already have this sound in cache
|
|
return result;
|
|
}
|
|
|
|
if( !fullName.isEmpty() )
|
|
{
|
|
QFile f( fullName );
|
|
if( f.open( QFile::WriteOnly | QFile::Truncate ) )
|
|
{
|
|
QByteArray buffer;
|
|
buffer.resize( BinaryBufferSize );
|
|
ssize_t length;
|
|
|
|
for( ; ; )
|
|
{
|
|
EB_Error_Code ret = eb_read_binary( &book, BinaryBufferSize,
|
|
buffer.data(), &length );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_binary", ret );
|
|
gdWarning( "Epwing sound retrieve error: %s",
|
|
error_string.toUtf8().data() );
|
|
break;
|
|
}
|
|
|
|
f.write( buffer.data(), length );
|
|
|
|
if( length < BinaryBufferSize )
|
|
break;
|
|
}
|
|
f.close();
|
|
|
|
soundsCacheList.append( name );
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QByteArray EpwingBook::handleMpeg( EB_Hook_Code code, const unsigned int * argv )
|
|
{
|
|
|
|
if( code == EB_HOOK_END_MPEG )
|
|
return QByteArray( "</a></span>" );
|
|
|
|
// Handle EB_HOOK_BEGIN_MPEG
|
|
|
|
char file[ EB_MAX_PATH_LENGTH + 1 ];
|
|
|
|
unsigned int *p = (unsigned int *)( argv + 2 );
|
|
eb_compose_movie_path_name( &book, p, file );
|
|
|
|
QString name = QString::fromLocal8Bit( file );
|
|
name = QFileInfo( name ).fileName();
|
|
name += ".mpg";
|
|
|
|
eb_set_binary_mpeg( &book, argv + 2 );
|
|
|
|
if( cacheMoviesDir.isEmpty() )
|
|
cacheMoviesDir = createCacheDir( "movies" );
|
|
|
|
QString fullName;
|
|
|
|
if( !cacheMoviesDir.isEmpty() )
|
|
fullName = cacheMoviesDir + QDir::separator() + name;
|
|
|
|
QUrl url;
|
|
url.setScheme( "gdvideo" );
|
|
url.setHost( dictID );
|
|
url.setPath( Utils::Url::ensureLeadingSlash( name ) );
|
|
|
|
QByteArray result = QByteArray( "<span class=\"epwing_mpeg\"><a href=" ) + url.toEncoded() + ">";
|
|
|
|
if( moviesCacheList.contains( name, Qt::CaseSensitive ) )
|
|
{
|
|
// We already have this movie in cache
|
|
return result;
|
|
}
|
|
|
|
if( !fullName.isEmpty() )
|
|
{
|
|
QFile f( fullName );
|
|
if( f.open( QFile::WriteOnly | QFile::Truncate ) )
|
|
{
|
|
QByteArray buffer;
|
|
buffer.resize( BinaryBufferSize );
|
|
ssize_t length;
|
|
|
|
for( ; ; )
|
|
{
|
|
EB_Error_Code ret = eb_read_binary( &book, BinaryBufferSize,
|
|
buffer.data(), &length );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_read_binary", ret );
|
|
gdWarning( "Epwing movie retrieve error: %s",
|
|
error_string.toUtf8().data() );
|
|
break;
|
|
}
|
|
|
|
f.write( buffer.data(), length );
|
|
|
|
if( length < BinaryBufferSize )
|
|
break;
|
|
}
|
|
f.close();
|
|
|
|
moviesCacheList.append( name );
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
QByteArray EpwingBook::codeToUnicode( QString const & code )
|
|
{
|
|
QString subst;
|
|
|
|
if( !customFontsMap.isEmpty() && customFontsMap.contains( code ) )
|
|
{
|
|
subst = QTextDocumentFragment::fromHtml( customFontsMap[ code ] )
|
|
.toPlainText();
|
|
return subst.toUtf8();
|
|
}
|
|
|
|
return EpwingCharmap::instance().mapToUtf8( code );
|
|
}
|
|
|
|
QByteArray EpwingBook::handleNarrowFont( const unsigned int * argv,
|
|
bool text_only )
|
|
{
|
|
QString fcode = "n" + QString::number( *argv, 16 );
|
|
|
|
// Check substitution list
|
|
|
|
QByteArray b = codeToUnicode( fcode );
|
|
if( !b.isEmpty() || text_only )
|
|
return b;
|
|
|
|
// Find font image in book
|
|
|
|
if( !eb_have_narrow_font( &book ) )
|
|
return QByteArray( "?" );
|
|
|
|
QString fname = fcode + ".png";
|
|
|
|
if( cacheFontsDir.isEmpty() )
|
|
cacheFontsDir = createCacheDir( "fonts" );
|
|
|
|
QString fullName = cacheFontsDir + QDir::separator() + fname;
|
|
|
|
QUrl url;
|
|
url.setScheme( "file" );
|
|
url.setHost( "/");
|
|
url.setPath( Utils::Url::ensureLeadingSlash( QDir::fromNativeSeparators( fullName ) ) );
|
|
|
|
QByteArray link = R"(<img class="epwing_narrow_font" src=")" + url.toEncoded() + "\"/>";
|
|
|
|
if( fontsCacheList.contains( fname, Qt::CaseSensitive ) )
|
|
{
|
|
// We already have this image in cache
|
|
return link;
|
|
}
|
|
|
|
if( !cacheFontsDir.isEmpty() )
|
|
{
|
|
char bitmap[EB_SIZE_NARROW_FONT_16];
|
|
EB_Error_Code ret = eb_narrow_font_character_bitmap( &book, *argv, bitmap );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_narrow_font_character_bitmap", ret );
|
|
gdWarning( "Epwing: Font retrieve error: %s", error_string.toUtf8().data() );
|
|
return QByteArray( "?" );
|
|
}
|
|
|
|
size_t nlen;
|
|
char buff[EB_SIZE_NARROW_FONT_16_PNG];
|
|
ret = eb_bitmap_to_png( bitmap, 8, 16, buff, &nlen );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_bitmap_to_png", ret );
|
|
gdWarning( "Epwing: Font retrieve error: %s", error_string.toUtf8().data() );
|
|
return QByteArray( "?" );
|
|
}
|
|
|
|
|
|
QFile f( fullName );
|
|
if( f.open( QFile::WriteOnly | QFile::Truncate ) )
|
|
{
|
|
f.write( buff, nlen );
|
|
f.close();
|
|
fontsCacheList.append( fname );
|
|
}
|
|
}
|
|
|
|
return link;
|
|
}
|
|
|
|
QByteArray EpwingBook::handleWideFont( const unsigned int * argv,
|
|
bool text_only )
|
|
{
|
|
QString fcode = "w" + QString::number( *argv, 16 );
|
|
|
|
// Check substitution list
|
|
|
|
QByteArray b = codeToUnicode( fcode );
|
|
if( !b.isEmpty() || text_only )
|
|
return b;
|
|
|
|
// Find font image in book
|
|
|
|
if( !eb_have_wide_font( &book ) )
|
|
return QByteArray( "?" );
|
|
|
|
QString fname = fcode + ".png";
|
|
|
|
if( cacheFontsDir.isEmpty() )
|
|
cacheFontsDir = createCacheDir( "fonts" );
|
|
|
|
QString fullName = cacheFontsDir + QDir::separator() + fname;
|
|
|
|
QUrl url;
|
|
url.setScheme( "file" );
|
|
url.setHost( "/");
|
|
url.setPath( Utils::Url::ensureLeadingSlash( QDir::fromNativeSeparators( fullName ) ) );
|
|
|
|
QByteArray link = R"(<img class="epwing_wide_font" src=")" + url.toEncoded() + "\"/>";
|
|
|
|
if( fontsCacheList.contains( fname, Qt::CaseSensitive ) )
|
|
{
|
|
// We already have this image in cache
|
|
return link;
|
|
}
|
|
|
|
if( !cacheFontsDir.isEmpty() )
|
|
{
|
|
char bitmap[EB_SIZE_WIDE_FONT_16];
|
|
EB_Error_Code ret = eb_wide_font_character_bitmap( &book, *argv, bitmap );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_wide_font_character_bitmap", ret );
|
|
gdWarning( "Epwing: Font retrieve error: %s", error_string.toUtf8().data() );
|
|
return QByteArray( "?" );
|
|
}
|
|
|
|
size_t wlen;
|
|
char buff[EB_SIZE_WIDE_FONT_16_PNG];
|
|
ret = eb_bitmap_to_png( bitmap, 16, 16, buff, &wlen );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_bitmap_to_png", ret );
|
|
gdWarning( "Epwing: Font retrieve error: %s", error_string.toUtf8().data() );
|
|
return QByteArray( "?" );
|
|
}
|
|
|
|
QFile f( fullName );
|
|
if( f.open( QFile::WriteOnly | QFile::Truncate ) )
|
|
{
|
|
f.write( buff, wlen );
|
|
f.close();
|
|
fontsCacheList.append( fname );
|
|
}
|
|
}
|
|
|
|
return link;
|
|
}
|
|
|
|
QByteArray EpwingBook::handleReference( EB_Hook_Code code, const unsigned int * argv )
|
|
{
|
|
if( code == EB_HOOK_BEGIN_REFERENCE )
|
|
{
|
|
if( refOpenCount > refCloseCount )
|
|
return QByteArray();
|
|
|
|
QString str=QString( "<R%1>").arg( refOpenCount );
|
|
refOpenCount += 1;
|
|
return str.toUtf8();
|
|
}
|
|
|
|
// EB_HOOK_END_REFERENCE
|
|
|
|
if( refCloseCount >= refOpenCount )
|
|
return QByteArray();
|
|
|
|
refPages.append( argv[ 1 ] );
|
|
refOffsets.append( argv[ 2 ] );
|
|
|
|
QString str = QString( "</R%1>" ).arg( refCloseCount );
|
|
refCloseCount += 1;
|
|
|
|
return str.toUtf8();
|
|
}
|
|
|
|
bool EpwingBook::getMatches( QString word, QVector< QString > & matches )
|
|
{
|
|
QByteArray bword, bword2;
|
|
EB_Hit hits[ HitsBufferSize ];
|
|
int hitCount = 0;
|
|
|
|
if( book.character_code == EB_CHARCODE_ISO8859_1 && codec_ISO )
|
|
bword = codec_ISO->fromUnicode( word );
|
|
else
|
|
if( ( book.character_code == EB_CHARCODE_JISX0208 || book.character_code == EB_CHARCODE_JISX0208_GB2312 )
|
|
&& codec_Euc )
|
|
bword = codec_Euc->fromUnicode( word );
|
|
|
|
if( book.character_code == EB_CHARCODE_JISX0208_GB2312 && codec_GB )
|
|
bword2 = codec_GB->fromUnicode( word );
|
|
|
|
if( !bword.isEmpty() )
|
|
{
|
|
EB_Error_Code ret = eb_search_word( &book, bword.data() );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_search_word", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
|
|
ret = eb_hit_list( &book, 10, hits, &hitCount );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_hit_list", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if( hitCount == 0 && !bword2.isEmpty() )
|
|
{
|
|
EB_Error_Code ret = eb_search_word( &book, bword2.data() );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_search_word", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
|
|
ret = eb_hit_list( &book, 10, hits, &hitCount );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_hit_list", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
QVector< int > pages, offsets;
|
|
|
|
for( int i = 0; i < hitCount; i++ )
|
|
{
|
|
bool same_article = false;
|
|
for( int n = 0; n < pages.size(); n++ )
|
|
{
|
|
if( pages.at( n ) == hits[ i ].text.page
|
|
&& offsets.at( n ) == hits[ i ].text.offset )
|
|
{
|
|
same_article = true;
|
|
continue;
|
|
}
|
|
}
|
|
if( !same_article )
|
|
{
|
|
pages.push_back( hits[ i ].text.page );
|
|
offsets.push_back( hits[ i ].text.offset );
|
|
|
|
QString headword;
|
|
if( readHeadword( hits[ i ].heading, headword, true ) )
|
|
{
|
|
if( isHeadwordCorrect( headword ) )
|
|
matches.push_back( headword );
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool EpwingBook::getArticlePos( QString word, QVector< int > & pages, QVector< int > & offsets )
|
|
{
|
|
QByteArray bword, bword2;
|
|
EB_Hit hits[ HitsBufferSize ];
|
|
int hitCount = 0;
|
|
|
|
if( book.character_code == EB_CHARCODE_ISO8859_1 && codec_ISO )
|
|
bword = codec_ISO->fromUnicode( word );
|
|
else
|
|
if( ( book.character_code == EB_CHARCODE_JISX0208 || book.character_code == EB_CHARCODE_JISX0208_GB2312 )
|
|
&& codec_Euc )
|
|
bword = codec_Euc->fromUnicode( word );
|
|
|
|
if( book.character_code == EB_CHARCODE_JISX0208_GB2312 && codec_GB )
|
|
bword2 = codec_GB->fromUnicode( word );
|
|
|
|
if( !bword.isEmpty() )
|
|
{
|
|
EB_Error_Code ret = eb_search_exactword( &book, bword.data() );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_search_word", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
|
|
ret = eb_hit_list( &book, HitsBufferSize, hits, &hitCount );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_hit_list", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if( hitCount == 0 && !bword2.isEmpty() )
|
|
{
|
|
EB_Error_Code ret = eb_search_exactword( &book, bword2.data() );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_search_word", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
|
|
ret = eb_hit_list( &book, HitsBufferSize, hits, &hitCount );
|
|
if( ret != EB_SUCCESS )
|
|
{
|
|
setErrorString( "eb_hit_list", ret );
|
|
gdWarning( "Epwing word search error: %s",
|
|
error_string.toUtf8().data() );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for( int i = 0; i < hitCount; i++ )
|
|
{
|
|
bool same_article = false;
|
|
for( int n = 0; n < pages.size(); n++ )
|
|
{
|
|
if( pages.at( n ) == hits[ i ].text.page
|
|
&& offsets.at( n ) == hits[ i ].text.offset )
|
|
{
|
|
same_article = true;
|
|
continue;
|
|
}
|
|
}
|
|
if( !same_article )
|
|
{
|
|
pages.push_back( hits[ i ].text.page );
|
|
offsets.push_back( hits[ i ].text.offset );
|
|
}
|
|
}
|
|
|
|
return !pages.empty();
|
|
}
|
|
|
|
Mutex EpwingBook::libMutex;
|
|
|
|
} // namespace Book
|
|
|
|
} // namespace Epwing
|