mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-30 17: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 "langcoder.hh"
|
||||
#include "dprintf.hh"
|
||||
#include "fsencoding.hh"
|
||||
#include "filetype.hh"
|
||||
|
||||
#include <zlib.h>
|
||||
#include <map>
|
||||
|
@ -159,6 +161,9 @@ public:
|
|||
wstring const & )
|
||||
throw( std::exception );
|
||||
|
||||
virtual sptr< Dictionary::DataRequest > getResource( string const & name )
|
||||
throw( std::exception );
|
||||
|
||||
private:
|
||||
|
||||
/// Retrives the article's offset/size in .dict file, and its headword.
|
||||
|
@ -174,6 +179,8 @@ private:
|
|||
|
||||
string loadString( size_t size );
|
||||
|
||||
string handleResource( char type, char const * resource, size_t size );
|
||||
|
||||
friend class StardictArticleRequest;
|
||||
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
|
||||
/// '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 )
|
||||
{
|
||||
case 'x': // Xdxf content
|
||||
return Xdxf2Html::convert( string( resource, size ) );
|
||||
return Xdxf2Html::convert( string( resource, size ), Xdxf2Html::STARDICT, NULL, this );
|
||||
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
|
||||
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
|
||||
|
@ -316,7 +330,7 @@ void StardictDictionary::loadArticle( uint32_t address,
|
|||
// the bytes left
|
||||
bool entrySizeKnown = ( seq == sameTypeSequence.size() - 1 );
|
||||
|
||||
uint32_t entrySize;
|
||||
uint32_t entrySize = 0;
|
||||
|
||||
if ( entrySizeKnown )
|
||||
entrySize = size;
|
||||
|
@ -994,6 +1008,157 @@ static void handleIdxSynFile( string const & fileName,
|
|||
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< string > const & fileNames,
|
||||
string const & indicesDir,
|
||||
|
|
39
xdxf2html.cc
39
xdxf2html.cc
|
@ -15,6 +15,16 @@
|
|||
|
||||
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 )
|
||||
{
|
||||
// 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" );
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
while( nodes.size() )
|
||||
{
|
||||
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() ) );
|
||||
|
||||
|
|
Loading…
Reference in a new issue