Support for images in Stardict dictionaries

This commit is contained in:
Abs62 2012-02-29 17:00:38 +04:00
parent 94fc7e72d3
commit f29e5b13cb
2 changed files with 207 additions and 5 deletions

View file

@ -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,

View file

@ -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() ) );