mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-24 00:14:06 +00:00
Zips: Search sounds both by short and full name (filename with/without extention)
This commit is contained in:
parent
025555c5ff
commit
b627c1e2d8
95
zipsounds.cc
95
zipsounds.cc
|
@ -11,6 +11,7 @@
|
||||||
#include "indexedzip.hh"
|
#include "indexedzip.hh"
|
||||||
#include "filetype.hh"
|
#include "filetype.hh"
|
||||||
#include "gddebug.hh"
|
#include "gddebug.hh"
|
||||||
|
#include "chunkedstorage.hh"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -42,7 +43,7 @@ DEF_EX( exInvalidData, "Invalid data encountered", Dictionary::Ex )
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Signature = 0x5350495a, // ZIPS on little-endian, SPIZ on big-endian
|
Signature = 0x5350495a, // ZIPS on little-endian, SPIZ on big-endian
|
||||||
CurrentFormatVersion = 2 + BtreeIndexing::FormatVersion
|
CurrentFormatVersion = 3 + BtreeIndexing::FormatVersion
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IdxHeader
|
struct IdxHeader
|
||||||
|
@ -52,6 +53,7 @@ struct IdxHeader
|
||||||
uint32_t soundsCount; // Total number of sounds, for informative purposes only
|
uint32_t soundsCount; // Total number of sounds, for informative purposes only
|
||||||
uint32_t indexBtreeMaxElements; // Two fields from IndexInfo
|
uint32_t indexBtreeMaxElements; // Two fields from IndexInfo
|
||||||
uint32_t indexRootOffset;
|
uint32_t indexRootOffset;
|
||||||
|
uint32_t chunksOffset; // The offset to chunks' storage
|
||||||
}
|
}
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
__attribute__((packed))
|
__attribute__((packed))
|
||||||
|
@ -103,6 +105,7 @@ class ZipSoundsDictionary: public BtreeIndexing::BtreeDictionary
|
||||||
Mutex idxMutex;
|
Mutex idxMutex;
|
||||||
File::Class idx;
|
File::Class idx;
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
sptr< ChunkedStorage::Reader > chunks;
|
||||||
IndexedZip zipsFile;
|
IndexedZip zipsFile;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -141,6 +144,8 @@ ZipSoundsDictionary::ZipSoundsDictionary( string const & id,
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, "rb" ),
|
||||||
idxHeader( idx.read< IdxHeader >() )
|
idxHeader( idx.read< IdxHeader >() )
|
||||||
{
|
{
|
||||||
|
chunks = new ChunkedStorage::Reader( idx, idxHeader.chunksOffset );
|
||||||
|
|
||||||
// Initialize the index
|
// Initialize the index
|
||||||
|
|
||||||
openIndex( IndexInfo( idxHeader.indexBtreeMaxElements,
|
openIndex( IndexInfo( idxHeader.indexBtreeMaxElements,
|
||||||
|
@ -183,7 +188,7 @@ sptr< Dictionary::DataRequest > ZipSoundsDictionary::getArticle( wstring const &
|
||||||
chain.insert( chain.end(), altChain.begin(), altChain.end() );
|
chain.insert( chain.end(), altChain.begin(), altChain.end() );
|
||||||
}
|
}
|
||||||
|
|
||||||
multimap< wstring, string > mainArticles, alternateArticles;
|
multimap< wstring, uint32_t > mainArticles, alternateArticles;
|
||||||
|
|
||||||
set< uint32_t > articlesIncluded; // Some synonims make it that the articles
|
set< uint32_t > articlesIncluded; // Some synonims make it that the articles
|
||||||
// appear several times. We combat this
|
// appear several times. We combat this
|
||||||
|
@ -204,12 +209,12 @@ sptr< Dictionary::DataRequest > ZipSoundsDictionary::getArticle( wstring const &
|
||||||
wstring headwordStripped =
|
wstring headwordStripped =
|
||||||
Folding::applySimpleCaseOnly( Utf8::decode( chain[ x ].word ) );
|
Folding::applySimpleCaseOnly( Utf8::decode( chain[ x ].word ) );
|
||||||
|
|
||||||
multimap< wstring, string > & mapToUse =
|
multimap< wstring, uint32_t > & mapToUse =
|
||||||
( wordCaseFolded == headwordStripped ) ?
|
( wordCaseFolded == headwordStripped ) ?
|
||||||
mainArticles : alternateArticles;
|
mainArticles : alternateArticles;
|
||||||
|
|
||||||
mapToUse.insert( std::pair< wstring, string >(
|
mapToUse.insert( std::pair< wstring, uint32_t >(
|
||||||
Folding::applySimpleCaseOnly( Utf8::decode( chain[ x ].word ) ), chain[ x ].word ) );
|
Folding::applySimpleCaseOnly( Utf8::decode( chain[ x ].word ) ), chain[ x ].articleOffset ) );
|
||||||
|
|
||||||
articlesIncluded.insert( chain[ x ].articleOffset );
|
articlesIncluded.insert( chain[ x ].articleOffset );
|
||||||
}
|
}
|
||||||
|
@ -219,42 +224,69 @@ sptr< Dictionary::DataRequest > ZipSoundsDictionary::getArticle( wstring const &
|
||||||
|
|
||||||
string result;
|
string result;
|
||||||
|
|
||||||
multimap< wstring, string >::const_iterator i;
|
multimap< wstring, uint32_t >::const_iterator i;
|
||||||
|
|
||||||
result += "<table class=\"lsa_play\">";
|
result += "<table class=\"lsa_play\">";
|
||||||
|
|
||||||
for( i = mainArticles.begin(); i != mainArticles.end(); ++i )
|
for( i = mainArticles.begin(); i != mainArticles.end(); ++i )
|
||||||
{
|
{
|
||||||
|
vector< char > chunk;
|
||||||
|
char * nameBlock = chunks->getBlock( i->second, chunk );
|
||||||
|
|
||||||
|
uint16_t sz;
|
||||||
|
memcpy( &sz, nameBlock, sizeof( uint16_t ) );
|
||||||
|
nameBlock += sizeof( uint16_t );
|
||||||
|
|
||||||
|
string name( nameBlock, sz );
|
||||||
|
nameBlock += sz;
|
||||||
|
|
||||||
|
string displayedName = mainArticles.size() + alternateArticles.size() > 1 ?
|
||||||
|
name : Utf8::encode( stripExtension( name ) );
|
||||||
|
|
||||||
result += "<tr>";
|
result += "<tr>";
|
||||||
|
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setScheme( "gdau" );
|
url.setScheme( "gdau" );
|
||||||
url.setHost( QString::fromUtf8( getId().c_str() ) );
|
url.setHost( QString::fromUtf8( getId().c_str() ) );
|
||||||
url.setPath( QString::fromUtf8( i->second.c_str() ) );
|
url.setPath( QString::fromUtf8( name.c_str() ) );
|
||||||
|
|
||||||
string ref = string( "\"" ) + url.toEncoded().data() + "\"";
|
string ref = string( "\"" ) + url.toEncoded().data() + "\"";
|
||||||
|
|
||||||
result += addAudioLink( ref, getId() );
|
result += addAudioLink( ref, getId() );
|
||||||
|
|
||||||
result += "<td><a href=" + ref + "><img src=\"qrcx://localhost/icons/playsound.png\" border=\"0\" alt=\"Play\"/></a></td>";
|
result += "<td><a href=" + ref + "><img src=\"qrcx://localhost/icons/playsound.png\" border=\"0\" alt=\"Play\"/></a></td>";
|
||||||
result += "<td><a href=" + ref + ">" + i->second + "</a></td>";
|
result += "<td><a href=" + ref + ">" + displayedName + "</a></td>";
|
||||||
result += "</tr>";
|
result += "</tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
for( i = alternateArticles.begin(); i != alternateArticles.end(); ++i )
|
for( i = alternateArticles.begin(); i != alternateArticles.end(); ++i )
|
||||||
{
|
{
|
||||||
|
vector< char > chunk;
|
||||||
|
char * nameBlock = chunks->getBlock( i->second, chunk );
|
||||||
|
|
||||||
|
uint16_t sz;
|
||||||
|
memcpy( &sz, nameBlock, sizeof( uint16_t ) );
|
||||||
|
nameBlock += sizeof( uint16_t );
|
||||||
|
|
||||||
|
string name( nameBlock, sz );
|
||||||
|
nameBlock += sz;
|
||||||
|
|
||||||
|
string displayedName = mainArticles.size() + alternateArticles.size() > 1 ?
|
||||||
|
name : Utf8::encode( stripExtension( name ) );
|
||||||
|
|
||||||
result += "<tr>";
|
result += "<tr>";
|
||||||
|
|
||||||
QUrl url;
|
QUrl url;
|
||||||
url.setScheme( "gdau" );
|
url.setScheme( "gdau" );
|
||||||
url.setHost( QString::fromUtf8( getId().c_str() ) );
|
url.setHost( QString::fromUtf8( getId().c_str() ) );
|
||||||
url.setPath( QString::fromUtf8( i->second.c_str() ) );
|
url.setPath( QString::fromUtf8( name.c_str() ) );
|
||||||
|
|
||||||
string ref = string( "\"" ) + url.toEncoded().data() + "\"";
|
string ref = string( "\"" ) + url.toEncoded().data() + "\"";
|
||||||
|
|
||||||
result += addAudioLink( ref, getId() );
|
result += addAudioLink( ref, getId() );
|
||||||
|
|
||||||
result += "<td><a href=" + ref + "><img src=\"qrcx://localhost/icons/playsound.png\" border=\"0\" alt=\"Play\"/></a></td>";
|
result += "<td><a href=" + ref + "><img src=\"qrcx://localhost/icons/playsound.png\" border=\"0\" alt=\"Play\"/></a></td>";
|
||||||
result += "<td><a href=" + ref + ">" + i->second + "</a></td>";
|
result += "<td><a href=" + ref + ">" + displayedName + "</a></td>";
|
||||||
result += "</tr>";
|
result += "</tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,10 +314,31 @@ sptr< Dictionary::DataRequest > ZipSoundsDictionary::getResource( string const &
|
||||||
if ( chain.empty() )
|
if ( chain.empty() )
|
||||||
return new Dictionary::DataRequestInstant( false ); // No such resource
|
return new Dictionary::DataRequestInstant( false ); // No such resource
|
||||||
|
|
||||||
|
// Find sound
|
||||||
|
|
||||||
|
uint32_t dataOffset = 0;
|
||||||
|
for( int x = chain.size() - 1; x >= 0 ; x-- )
|
||||||
|
{
|
||||||
|
vector< char > chunk;
|
||||||
|
char * nameBlock = chunks->getBlock( chain[ x ].articleOffset, chunk );
|
||||||
|
|
||||||
|
uint16_t sz;
|
||||||
|
memcpy( &sz, nameBlock, sizeof( uint16_t ) );
|
||||||
|
nameBlock += sizeof( uint16_t );
|
||||||
|
|
||||||
|
string fileName( nameBlock, sz );
|
||||||
|
nameBlock += sz;
|
||||||
|
|
||||||
|
memcpy( &dataOffset, nameBlock, sizeof( uint32_t ) );
|
||||||
|
|
||||||
|
if( name.compare( fileName ) == 0 )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
sptr< Dictionary::DataRequestInstant > dr = new
|
sptr< Dictionary::DataRequestInstant > dr = new
|
||||||
Dictionary::DataRequestInstant( true );
|
Dictionary::DataRequestInstant( true );
|
||||||
|
|
||||||
if ( zipsFile.loadFile( chain[ 0 ].articleOffset, dr->getData() ) )
|
if ( zipsFile.loadFile( dataOffset, dr->getData() ) )
|
||||||
return dr;
|
return dr;
|
||||||
|
|
||||||
return new Dictionary::DataRequestInstant( false );
|
return new Dictionary::DataRequestInstant( false );
|
||||||
|
@ -351,6 +404,8 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
|
||||||
idx.write( idxHeader );
|
idx.write( idxHeader );
|
||||||
|
|
||||||
IndexedWords names, zipFileNames;
|
IndexedWords names, zipFileNames;
|
||||||
|
ChunkedStorage::Writer chunks( idx );
|
||||||
|
|
||||||
IndexedZip zipFile;
|
IndexedZip zipFile;
|
||||||
if( zipFile.openZipFile( QDir::fromNativeSeparators(
|
if( zipFile.openZipFile( QDir::fromNativeSeparators(
|
||||||
FsEncoding::decode( i->c_str() ) ) ) )
|
FsEncoding::decode( i->c_str() ) ) ) )
|
||||||
|
@ -358,19 +413,31 @@ vector< sptr< Dictionary::Class > > makeDictionaries(
|
||||||
|
|
||||||
if( !zipFileNames.empty() )
|
if( !zipFileNames.empty() )
|
||||||
{
|
{
|
||||||
// Remove extension for sound files (like in sound dirs)
|
|
||||||
|
|
||||||
for( IndexedWords::iterator i = zipFileNames.begin(); i != zipFileNames.end(); ++i )
|
for( IndexedWords::iterator i = zipFileNames.begin(); i != zipFileNames.end(); ++i )
|
||||||
{
|
{
|
||||||
vector< WordArticleLink > links = i->second;
|
vector< WordArticleLink > links = i->second;
|
||||||
for( unsigned x = 0; x < links.size(); x++ )
|
for( unsigned x = 0; x < links.size(); x++ )
|
||||||
{
|
{
|
||||||
|
// Save original name
|
||||||
|
|
||||||
|
uint32_t offset = chunks.startNewBlock();
|
||||||
|
uint16_t sz = links[ x ].word.size();
|
||||||
|
chunks.addToBlock( &sz, sizeof(uint16_t) );
|
||||||
|
chunks.addToBlock( links[ x ].word.c_str(), sz );
|
||||||
|
chunks.addToBlock( &links[ x ].articleOffset, sizeof( uint32_t ) );
|
||||||
|
|
||||||
|
// Remove extension for sound files (like in sound dirs)
|
||||||
|
|
||||||
wstring word = stripExtension( links[ x ].word );
|
wstring word = stripExtension( links[ x ].word );
|
||||||
if( !word.empty() )
|
if( !word.empty() )
|
||||||
names.addSingleWord( word, links[ x ].articleOffset );
|
names.addSingleWord( word, offset );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finish with the chunks
|
||||||
|
|
||||||
|
idxHeader.chunksOffset = chunks.finish();
|
||||||
|
|
||||||
// Build the resulting zip file index
|
// Build the resulting zip file index
|
||||||
|
|
||||||
IndexInfo idxInfo = BtreeIndexing::buildIndex( names, idx );
|
IndexInfo idxInfo = BtreeIndexing::buildIndex( names, idx );
|
||||||
|
|
Loading…
Reference in a new issue