mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-27 19:24:08 +00:00
Support for images in Stardict dictionaries
This commit is contained in:
parent
94fc7e72d3
commit
f29e5b13cb
173
stardict.cc
173
stardict.cc
|
@ -11,6 +11,8 @@
|
||||||
#include "htmlescape.hh"
|
#include "htmlescape.hh"
|
||||||
#include "langcoder.hh"
|
#include "langcoder.hh"
|
||||||
#include "dprintf.hh"
|
#include "dprintf.hh"
|
||||||
|
#include "fsencoding.hh"
|
||||||
|
#include "filetype.hh"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -159,6 +161,9 @@ public:
|
||||||
wstring const & )
|
wstring const & )
|
||||||
throw( std::exception );
|
throw( std::exception );
|
||||||
|
|
||||||
|
virtual sptr< Dictionary::DataRequest > getResource( string const & name )
|
||||||
|
throw( std::exception );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// Retrives the article's offset/size in .dict file, and its headword.
|
/// Retrives the article's offset/size in .dict file, and its headword.
|
||||||
|
@ -174,6 +179,8 @@ private:
|
||||||
|
|
||||||
string loadString( size_t size );
|
string loadString( size_t size );
|
||||||
|
|
||||||
|
string handleResource( char type, char const * resource, size_t size );
|
||||||
|
|
||||||
friend class StardictArticleRequest;
|
friend class StardictArticleRequest;
|
||||||
friend class StardictHeadwordsRequest;
|
friend class StardictHeadwordsRequest;
|
||||||
};
|
};
|
||||||
|
@ -237,14 +244,21 @@ void StardictDictionary::getArticleProps( uint32_t articleAddress,
|
||||||
|
|
||||||
/// This function tries to make an html of the Stardict's resource typed
|
/// This function tries to make an html of the Stardict's resource typed
|
||||||
/// 'type', contained in a block pointed to by 'resource', 'size' bytes long.
|
/// 'type', contained in a block pointed to by 'resource', 'size' bytes long.
|
||||||
static string handleResource( char type, char const * resource, size_t size )
|
string StardictDictionary::handleResource( char type, char const * resource, size_t size )
|
||||||
{
|
{
|
||||||
switch( type )
|
switch( type )
|
||||||
{
|
{
|
||||||
case 'x': // Xdxf content
|
case 'x': // Xdxf content
|
||||||
return Xdxf2Html::convert( string( resource, size ) );
|
return Xdxf2Html::convert( string( resource, size ), Xdxf2Html::STARDICT, NULL, this );
|
||||||
case 'h': // Html content
|
case 'h': // Html content
|
||||||
return "<div class=\"sdct_h\">" + string( resource, size ) + "</div>";
|
{
|
||||||
|
string articleText = "<div class=\"sdct_h\">" + string( resource, size ) + "</div>";
|
||||||
|
|
||||||
|
return ( QString::fromUtf8( articleText.c_str() )
|
||||||
|
.replace( QRegExp( "(<\\s*img\\s+[^>]*src\\s*=\\s*[\"']*)([^\"']*)", Qt::CaseInsensitive ),
|
||||||
|
"\\1bres://" + QString::fromStdString( getId() ) + "/\\2" )
|
||||||
|
.toUtf8().data() );
|
||||||
|
}
|
||||||
case 'm': // Pure meaning, usually means preformatted text
|
case 'm': // Pure meaning, usually means preformatted text
|
||||||
return "<div class=\"sdct_m\">" + Html::preformat( string( resource, size ) ) + "</div>";
|
return "<div class=\"sdct_m\">" + Html::preformat( string( resource, size ) ) + "</div>";
|
||||||
case 'l': // Same as 'm', but not in utf8, instead in current locale's
|
case 'l': // Same as 'm', but not in utf8, instead in current locale's
|
||||||
|
@ -316,7 +330,7 @@ void StardictDictionary::loadArticle( uint32_t address,
|
||||||
// the bytes left
|
// the bytes left
|
||||||
bool entrySizeKnown = ( seq == sameTypeSequence.size() - 1 );
|
bool entrySizeKnown = ( seq == sameTypeSequence.size() - 1 );
|
||||||
|
|
||||||
uint32_t entrySize;
|
uint32_t entrySize = 0;
|
||||||
|
|
||||||
if ( entrySizeKnown )
|
if ( entrySizeKnown )
|
||||||
entrySize = size;
|
entrySize = size;
|
||||||
|
@ -994,6 +1008,157 @@ static void handleIdxSynFile( string const & fileName,
|
||||||
DPRINTF( "%u entires made\n", indexedWords.size() );
|
DPRINTF( "%u entires made\n", indexedWords.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// StardictDictionary::getResource()
|
||||||
|
|
||||||
|
class StardictResourceRequest;
|
||||||
|
|
||||||
|
class StardictResourceRequestRunnable: public QRunnable
|
||||||
|
{
|
||||||
|
StardictResourceRequest & r;
|
||||||
|
QSemaphore & hasExited;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
StardictResourceRequestRunnable( StardictResourceRequest & r_,
|
||||||
|
QSemaphore & hasExited_ ): r( r_ ),
|
||||||
|
hasExited( hasExited_ )
|
||||||
|
{}
|
||||||
|
|
||||||
|
~StardictResourceRequestRunnable()
|
||||||
|
{
|
||||||
|
hasExited.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
class StardictResourceRequest: public Dictionary::DataRequest
|
||||||
|
{
|
||||||
|
friend class StardictResourceRequestRunnable;
|
||||||
|
|
||||||
|
StardictDictionary & dict;
|
||||||
|
|
||||||
|
string resourceName;
|
||||||
|
|
||||||
|
QAtomicInt isCancelled;
|
||||||
|
QSemaphore hasExited;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
StardictResourceRequest( StardictDictionary & dict_,
|
||||||
|
string const & resourceName_ ):
|
||||||
|
dict( dict_ ),
|
||||||
|
resourceName( resourceName_ )
|
||||||
|
{
|
||||||
|
QThreadPool::globalInstance()->start(
|
||||||
|
new StardictResourceRequestRunnable( *this, hasExited ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(); // Run from another thread by StardictResourceRequestRunnable
|
||||||
|
|
||||||
|
virtual void cancel()
|
||||||
|
{
|
||||||
|
isCancelled.ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
~StardictResourceRequest()
|
||||||
|
{
|
||||||
|
isCancelled.ref();
|
||||||
|
hasExited.acquire();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void StardictResourceRequestRunnable::run()
|
||||||
|
{
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StardictResourceRequest::run()
|
||||||
|
{
|
||||||
|
// Some runnables linger enough that they are cancelled before they start
|
||||||
|
if ( isCancelled )
|
||||||
|
{
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if( resourceName.at( 0 ) == '\x1E' )
|
||||||
|
resourceName = resourceName.erase( 0, 1 );
|
||||||
|
if( resourceName.at( resourceName.length() - 1 ) == '\x1F' )
|
||||||
|
resourceName.erase( resourceName.length() - 1, 1 );
|
||||||
|
|
||||||
|
string n =
|
||||||
|
FsEncoding::dirname( dict.getDictionaryFilenames()[ 0 ] ) +
|
||||||
|
FsEncoding::separator() +
|
||||||
|
"res" +
|
||||||
|
FsEncoding::separator() +
|
||||||
|
FsEncoding::encode( resourceName );
|
||||||
|
|
||||||
|
DPRINTF( "n is %s\n", n.c_str() );
|
||||||
|
|
||||||
|
{
|
||||||
|
Mutex::Lock _( dataMutex );
|
||||||
|
|
||||||
|
File::loadFromFile( n, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Filetype::isNameOfTiff( resourceName ) )
|
||||||
|
{
|
||||||
|
// Convert it
|
||||||
|
|
||||||
|
dataMutex.lock();
|
||||||
|
|
||||||
|
QImage img = QImage::fromData( (unsigned char *) &data.front(),
|
||||||
|
data.size() );
|
||||||
|
|
||||||
|
dataMutex.unlock();
|
||||||
|
|
||||||
|
if ( !img.isNull() )
|
||||||
|
{
|
||||||
|
// Managed to load -- now store it back as BMP
|
||||||
|
|
||||||
|
QByteArray ba;
|
||||||
|
QBuffer buffer( &ba );
|
||||||
|
buffer.open( QIODevice::WriteOnly );
|
||||||
|
img.save( &buffer, "BMP" );
|
||||||
|
|
||||||
|
Mutex::Lock _( dataMutex );
|
||||||
|
|
||||||
|
data.resize( buffer.size() );
|
||||||
|
|
||||||
|
memcpy( &data.front(), buffer.data(), data.size() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutex::Lock _( dataMutex );
|
||||||
|
|
||||||
|
hasAnyData = true;
|
||||||
|
}
|
||||||
|
catch( File::Ex & )
|
||||||
|
{
|
||||||
|
// No such resource -- we don't set the hasAnyData flag then
|
||||||
|
}
|
||||||
|
catch( Utf8::exCantDecode )
|
||||||
|
{
|
||||||
|
// Failed to decode some utf8 -- probably the resource name is no good
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
sptr< Dictionary::DataRequest > StardictDictionary::getResource( string const & name )
|
||||||
|
throw( std::exception )
|
||||||
|
{
|
||||||
|
return new StardictResourceRequest( *this, name );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
vector< sptr< Dictionary::Class > > makeDictionaries(
|
vector< sptr< Dictionary::Class > > makeDictionaries(
|
||||||
vector< string > const & fileNames,
|
vector< string > const & fileNames,
|
||||||
string const & indicesDir,
|
string const & indicesDir,
|
||||||
|
|
39
xdxf2html.cc
39
xdxf2html.cc
|
@ -15,6 +15,16 @@
|
||||||
|
|
||||||
namespace Xdxf2Html {
|
namespace Xdxf2Html {
|
||||||
|
|
||||||
|
static void fixLink( QDomElement & el, string const & dictId, const char *attrName )
|
||||||
|
{
|
||||||
|
QUrl url;
|
||||||
|
url.setScheme( "bres" );
|
||||||
|
url.setHost( QString::fromStdString(dictId) );
|
||||||
|
url.setPath( el.attribute(attrName) );
|
||||||
|
|
||||||
|
el.setAttribute( attrName, url.toEncoded().data() );
|
||||||
|
}
|
||||||
|
|
||||||
string convert( string const & in, DICT_TYPE type, map < string, string > const * pAbrv, Dictionary::Class *dictPtr )
|
string convert( string const & in, DICT_TYPE type, map < string, string > const * pAbrv, Dictionary::Class *dictPtr )
|
||||||
{
|
{
|
||||||
// DPRINTF( "Source>>>>>>>>>>: %s\n\n\n", in.c_str() );
|
// DPRINTF( "Source>>>>>>>>>>: %s\n\n\n", in.c_str() );
|
||||||
|
@ -220,13 +230,40 @@ string convert( string const & in, DICT_TYPE type, map < string, string > const
|
||||||
el.setAttribute( "class", "xdxf_tr" );
|
el.setAttribute( "class", "xdxf_tr" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that ArticleNetworkAccessManager can deal with XDXF images.
|
||||||
|
// We modify the URL by using the dictionary ID as the hostname.
|
||||||
|
// This is necessary to determine from which dictionary a requested
|
||||||
|
// image originates.
|
||||||
|
nodes = dd.elementsByTagName( "img" );
|
||||||
|
|
||||||
|
for( int i = 0; i < nodes.size(); i++ )
|
||||||
|
{
|
||||||
|
QDomElement el = nodes.at( i ).toElement();
|
||||||
|
|
||||||
|
if ( el.hasAttribute( "src" ) )
|
||||||
|
{
|
||||||
|
fixLink( el, dictPtr->getId(), "src" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( el.hasAttribute( "losrc" ) )
|
||||||
|
{
|
||||||
|
fixLink( el, dictPtr->getId(), "losrc" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( el.hasAttribute( "hisrc" ) )
|
||||||
|
{
|
||||||
|
fixLink( el, dictPtr->getId(), "hisrc" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nodes = dd.elementsByTagName( "rref" ); // Resource reference
|
nodes = dd.elementsByTagName( "rref" ); // Resource reference
|
||||||
|
|
||||||
while( nodes.size() )
|
while( nodes.size() )
|
||||||
{
|
{
|
||||||
QDomElement el = nodes.at( 0 ).toElement();
|
QDomElement el = nodes.at( 0 ).toElement();
|
||||||
|
|
||||||
if( type == XDXF && dictPtr != NULL && !el.hasAttribute( "start" ) )
|
// if( type == XDXF && dictPtr != NULL && !el.hasAttribute( "start" ) )
|
||||||
|
if( dictPtr != NULL && !el.hasAttribute( "start" ) )
|
||||||
{
|
{
|
||||||
string filename = Utf8::encode( gd::toWString( el.text() ) );
|
string filename = Utf8::encode( gd::toWString( el.text() ) );
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue