mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-23 20:14:05 +00:00
Compare commits
11 commits
9f8b449c3e
...
95b57a1a3c
Author | SHA1 | Date | |
---|---|---|---|
95b57a1a3c | |||
fa9ad2fdf7 | |||
8f42e2e073 | |||
c892083b00 | |||
2d6e2a85ee | |||
1fa0771716 | |||
bb87c55b1a | |||
652da8e1ec | |||
15b918eb6a | |||
27cbb7351b | |||
c787a08d2f |
7
.github/workflows/PR-check-cmake.yml
vendored
7
.github/workflows/PR-check-cmake.yml
vendored
|
@ -51,6 +51,9 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: false
|
submodules: false
|
||||||
|
- name: Update brew
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
brew install \
|
brew install \
|
||||||
|
@ -66,11 +69,11 @@ jobs:
|
||||||
xapian \
|
xapian \
|
||||||
libzim \
|
libzim \
|
||||||
qt
|
qt
|
||||||
|
- name: Install eb
|
||||||
|
run: |
|
||||||
wget https://github.com/mistydemeo/eb/releases/download/v4.4.3/eb-4.4.3.tar.bz2
|
wget https://github.com/mistydemeo/eb/releases/download/v4.4.3/eb-4.4.3.tar.bz2
|
||||||
tar xvjf eb-4.4.3.tar.bz2
|
tar xvjf eb-4.4.3.tar.bz2
|
||||||
cd eb-4.4.3 && ./configure && make -j 8 && sudo make install && cd ..
|
cd eb-4.4.3 && ./configure && make -j 8 && sudo make install && cd ..
|
||||||
|
|
||||||
- name: Run build
|
- name: Run build
|
||||||
run: |
|
run: |
|
||||||
mkdir build_dir
|
mkdir build_dir
|
||||||
|
|
9
.github/workflows/Release-all.yml
vendored
9
.github/workflows/Release-all.yml
vendored
|
@ -26,6 +26,9 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
- name: Update brew
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
brew install \
|
brew install \
|
||||||
|
@ -40,7 +43,8 @@ jobs:
|
||||||
ninja \
|
ninja \
|
||||||
opencc \
|
opencc \
|
||||||
xapian
|
xapian
|
||||||
|
- name: Install eb
|
||||||
|
run: |
|
||||||
git clone https://github.com/xiaoyifang/eb.git
|
git clone https://github.com/xiaoyifang/eb.git
|
||||||
cd eb && ./configure && make -j 8 && sudo make install && cd ..
|
cd eb && ./configure && make -j 8 && sudo make install && cd ..
|
||||||
- uses: jurplel/install-qt-action@v4
|
- uses: jurplel/install-qt-action@v4
|
||||||
|
@ -61,6 +65,9 @@ jobs:
|
||||||
- name: Package
|
- name: Package
|
||||||
run: |
|
run: |
|
||||||
cmake --install build_dir/
|
cmake --install build_dir/
|
||||||
|
- name: Print package content
|
||||||
|
run: |
|
||||||
|
ls -Rl ./build_dir/redist
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: macOS-${{ matrix.os }}-Qt${{ matrix.qt_ver }}
|
name: macOS-${{ matrix.os }}-Qt${{ matrix.qt_ver }}
|
||||||
|
|
|
@ -284,6 +284,7 @@ if (APPLE)
|
||||||
set(QT_DEPLOY_TRANSLATIONS_DIR \"Contents/Resources/translations\")
|
set(QT_DEPLOY_TRANSLATIONS_DIR \"Contents/Resources/translations\")
|
||||||
qt_deploy_runtime_dependencies(
|
qt_deploy_runtime_dependencies(
|
||||||
EXECUTABLE \"${Redistributable_APP}\"
|
EXECUTABLE \"${Redistributable_APP}\"
|
||||||
|
ADDITIONAL_LIBRARIES ${BREW_ICU_ADDITIONAL_DYLIBS}
|
||||||
GENERATE_QT_CONF
|
GENERATE_QT_CONF
|
||||||
NO_APP_STORE_COMPLIANCE)
|
NO_APP_STORE_COMPLIANCE)
|
||||||
qt_deploy_translations()
|
qt_deploy_translations()
|
||||||
|
|
|
@ -79,30 +79,25 @@ endif ()
|
||||||
if (WITH_ZIM)
|
if (WITH_ZIM)
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# ICU from homebrew is "key-only", we need to manually prioritize it -> see `brew info icu4c`
|
# ICU from homebrew is "key-only", we need to manually prioritize it -> see `brew info icu4c`
|
||||||
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/opt/icu4c@76/lib/pkgconfig:/opt/homebrew/opt/icu4c@76/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig:/opt/homebrew/opt/icu4c/lib/pkgconfig")
|
# And we needs to find the correct one if multiple versions co exists.
|
||||||
|
set(ENV{PATH} "$ENV{PATH}:/usr/local/bin/:/opt/homebrew/bin") # add brew command into PATH
|
||||||
|
execute_process(
|
||||||
|
COMMAND sh -c [=[brew --prefix $(brew deps libzim | grep icu4c)]=]
|
||||||
|
OUTPUT_VARIABLE ICU_REQUIRED_BY_ZIM_PREFIX
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY)
|
||||||
|
message(STATUS "Found correct homebrew icu path -> ${ICU_REQUIRED_BY_ZIM_PREFIX}")
|
||||||
|
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/pkgconfig")
|
||||||
|
message(STATUS "Updated pkg_config_path -> $ENV{PKG_CONFIG_PATH}:${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/pkgconfig")
|
||||||
|
|
||||||
|
# icu4c as transitive dependency of libzim may not be automatically copied into app bundle
|
||||||
|
# so we manually discover the icu4c from homebrew, then find the relevent dylibs
|
||||||
|
set(BREW_ICU_ADDITIONAL_DYLIBS "${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/libicudata.dylib ${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/libicui18n.dylib ${ICU_REQUIRED_BY_ZIM_PREFIX}/lib/libicuuc.dylib")
|
||||||
|
message(STATUS "Additional ICU `.dylib`s -> ${BREW_ICU_ADDITIONAL_DYLIBS}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
pkg_check_modules(ZIM REQUIRED IMPORTED_TARGET libzim)
|
pkg_check_modules(ZIM REQUIRED IMPORTED_TARGET libzim)
|
||||||
target_link_libraries(${GOLDENDICT} PRIVATE PkgConfig::ZIM)
|
target_link_libraries(${GOLDENDICT} PRIVATE PkgConfig::ZIM)
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
# icu4c as transitive dependency of libzim may not be copied into app bundle, so we directly depends on it to assist macdeployqt
|
|
||||||
# Why such complexities: 1) System or XCode SDKS's icu exists 2) icu itself is depended by various stuffs and homebrew may need multiple versions of it
|
|
||||||
pkg_check_modules(BREW_ICU REQUIRED IMPORTED_TARGET icu-i18n icu-uc)
|
|
||||||
target_link_libraries(${GOLDENDICT} PUBLIC PkgConfig::BREW_ICU)
|
|
||||||
|
|
||||||
# Verify icu <-> zim matches
|
|
||||||
message("Zim include dirs -> ${ZIM_INCLUDE_DIRS}")
|
|
||||||
message("Homebrew icu include dirs-> ${BREW_ICU_INCLUDE_DIRS}")
|
|
||||||
|
|
||||||
list(GET BREW_ICU_INCLUDE_DIRS 0 ONE_OF_BREW_ICU_INCLUDE_DIR)
|
|
||||||
if (ONE_OF_BREW_ICU_INCLUDE_DIR IN_LIST ZIM_INCLUDE_DIRS)
|
|
||||||
message("ZIM OK!")
|
|
||||||
else ()
|
|
||||||
message(FATAL_ERROR "!!!! ZIM <-> icu error -> check `brew info libzim` and `brew list libzim`")
|
|
||||||
endif ()
|
|
||||||
# TODO: get rid of these 💩, how?
|
|
||||||
endif ()
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (USE_SYSTEM_FMT)
|
if (USE_SYSTEM_FMT)
|
||||||
|
|
|
@ -257,9 +257,14 @@ inline bool isAudioUrl( QUrl const & url )
|
||||||
{
|
{
|
||||||
if ( !url.isValid() )
|
if ( !url.isValid() )
|
||||||
return false;
|
return false;
|
||||||
// Note: we check for forvo sound links explicitly, as they don't have extensions
|
|
||||||
|
|
||||||
return ( url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gdau" )
|
// gdau links are known to be audios, (sometimes they may not have file extension).
|
||||||
|
if ( url.scheme() == "gdau" ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: we check for forvo sound links explicitly, as they don't have extensions
|
||||||
|
return ( url.scheme() == "http" || url.scheme() == "https" )
|
||||||
&& ( Filetype::isNameOfSound( url.path().toUtf8().data() ) || url.host() == "apifree.forvo.com" );
|
&& ( Filetype::isNameOfSound( url.path().toUtf8().data() ) || url.host() == "apifree.forvo.com" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,6 +150,7 @@ Preferences::Preferences():
|
||||||
doubleClickTranslates( true ),
|
doubleClickTranslates( true ),
|
||||||
selectWordBySingleClick( false ),
|
selectWordBySingleClick( false ),
|
||||||
autoScrollToTargetArticle( true ),
|
autoScrollToTargetArticle( true ),
|
||||||
|
targetArticleAtFirst( false ),
|
||||||
escKeyHidesMainWindow( false ),
|
escKeyHidesMainWindow( false ),
|
||||||
alwaysOnTop( false ),
|
alwaysOnTop( false ),
|
||||||
searchInDock( false ),
|
searchInDock( false ),
|
||||||
|
@ -878,6 +879,11 @@ Class load()
|
||||||
( preferences.namedItem( "autoScrollToTargetArticle" ).toElement().text() == "1" );
|
( preferences.namedItem( "autoScrollToTargetArticle" ).toElement().text() == "1" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !preferences.namedItem( "targetArticleAtFirst" ).isNull() ) {
|
||||||
|
c.preferences.targetArticleAtFirst =
|
||||||
|
( preferences.namedItem( "targetArticleAtFirst" ).toElement().text() == "1" );
|
||||||
|
}
|
||||||
|
|
||||||
if ( !preferences.namedItem( "escKeyHidesMainWindow" ).isNull() ) {
|
if ( !preferences.namedItem( "escKeyHidesMainWindow" ).isNull() ) {
|
||||||
c.preferences.escKeyHidesMainWindow =
|
c.preferences.escKeyHidesMainWindow =
|
||||||
( preferences.namedItem( "escKeyHidesMainWindow" ).toElement().text() == "1" );
|
( preferences.namedItem( "escKeyHidesMainWindow" ).toElement().text() == "1" );
|
||||||
|
@ -1815,6 +1821,10 @@ void save( Class const & c )
|
||||||
opt.appendChild( dd.createTextNode( c.preferences.autoScrollToTargetArticle ? "1" : "0" ) );
|
opt.appendChild( dd.createTextNode( c.preferences.autoScrollToTargetArticle ? "1" : "0" ) );
|
||||||
preferences.appendChild( opt );
|
preferences.appendChild( opt );
|
||||||
|
|
||||||
|
opt = dd.createElement( "targetArticleAtFirst" );
|
||||||
|
opt.appendChild( dd.createTextNode( c.preferences.targetArticleAtFirst ? "1" : "0" ) );
|
||||||
|
preferences.appendChild( opt );
|
||||||
|
|
||||||
opt = dd.createElement( "escKeyHidesMainWindow" );
|
opt = dd.createElement( "escKeyHidesMainWindow" );
|
||||||
opt.appendChild( dd.createTextNode( c.preferences.escKeyHidesMainWindow ? "1" : "0" ) );
|
opt.appendChild( dd.createTextNode( c.preferences.escKeyHidesMainWindow ? "1" : "0" ) );
|
||||||
preferences.appendChild( opt );
|
preferences.appendChild( opt );
|
||||||
|
|
|
@ -297,6 +297,7 @@ struct Preferences
|
||||||
bool doubleClickTranslates;
|
bool doubleClickTranslates;
|
||||||
bool selectWordBySingleClick;
|
bool selectWordBySingleClick;
|
||||||
bool autoScrollToTargetArticle;
|
bool autoScrollToTargetArticle;
|
||||||
|
bool targetArticleAtFirst;
|
||||||
bool escKeyHidesMainWindow;
|
bool escKeyHidesMainWindow;
|
||||||
bool alwaysOnTop;
|
bool alwaysOnTop;
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -287,10 +287,10 @@ private:
|
||||||
|
|
||||||
AardDictionary::AardDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
AardDictionary::AardDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
chunks( idx, idxHeader.chunksOffset ),
|
chunks( idx, idxHeader.chunksOffset ),
|
||||||
df( dictionaryFiles[ 0 ], "rb" )
|
df( dictionaryFiles[ 0 ], QIODevice::ReadOnly )
|
||||||
{
|
{
|
||||||
// Read dictionary name
|
// Read dictionary name
|
||||||
|
|
||||||
|
@ -802,7 +802,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File::Index df( fileName, "rb" );
|
File::Index df( fileName, QIODevice::ReadOnly );
|
||||||
|
|
||||||
AAR_header dictHeader;
|
AAR_header dictHeader;
|
||||||
|
|
||||||
|
@ -871,7 +871,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
initializing.indexingDictionary( dictName );
|
initializing.indexingDictionary( dictName );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ private:
|
||||||
|
|
||||||
BglDictionary::BglDictionary( string const & id, string const & indexFile, string const & dictionaryFile ):
|
BglDictionary::BglDictionary( string const & id, string const & indexFile, string const & dictionaryFile ):
|
||||||
BtreeDictionary( id, vector< string >( 1, dictionaryFile ) ),
|
BtreeDictionary( id, vector< string >( 1, dictionaryFile ) ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
chunks( idx, idxHeader.chunksOffset )
|
chunks( idx, idxHeader.chunksOffset )
|
||||||
{
|
{
|
||||||
|
@ -1083,7 +1083,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
initializing.indexingDictionary( b.title() );
|
initializing.indexingDictionary( b.title() );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -155,8 +155,8 @@ DictdDictionary::DictdDictionary( string const & id,
|
||||||
string const & indexFile,
|
string const & indexFile,
|
||||||
vector< string > const & dictionaryFiles ):
|
vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
indexFile( dictionaryFiles[ 0 ], "rb" ),
|
indexFile( dictionaryFiles[ 0 ], QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() )
|
idxHeader( idx.read< IdxHeader >() )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -606,7 +606,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
initializing.indexingDictionary( dictionaryName );
|
initializing.indexingDictionary( dictionaryName );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
|
@ -619,7 +619,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
IndexedWords indexedWords;
|
IndexedWords indexedWords;
|
||||||
|
|
||||||
File::Index indexFile( dictFiles[ 0 ], "rb" );
|
File::Index indexFile( dictFiles[ 0 ], QIODevice::ReadOnly );
|
||||||
|
|
||||||
// Read words from index until none's left.
|
// Read words from index until none's left.
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ struct InsidedCard
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile, bool hasZipFile )
|
bool indexIsOldOrBad( string const & indexFile, bool hasZipFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ private:
|
||||||
|
|
||||||
DslDictionary::DslDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
DslDictionary::DslDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
dz( 0 ),
|
dz( 0 ),
|
||||||
deferredInitRunnableStarted( false ),
|
deferredInitRunnableStarted( false ),
|
||||||
|
@ -1807,7 +1807,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
gdDebug( "Dsl: Building the index for dictionary: %s\n",
|
gdDebug( "Dsl: Building the index for dictionary: %s\n",
|
||||||
QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() );
|
QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ EpwingDictionary::EpwingDictionary( string const & id,
|
||||||
vector< string > const & dictionaryFiles,
|
vector< string > const & dictionaryFiles,
|
||||||
int subBook ):
|
int subBook ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
chunks( idx, idxHeader.chunksOffset )
|
chunks( idx, idxHeader.chunksOffset )
|
||||||
{
|
{
|
||||||
|
@ -1197,7 +1197,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
QByteArray nameData = str.toUtf8();
|
QByteArray nameData = str.toUtf8();
|
||||||
initializing.indexingDictionary( nameData.data() );
|
initializing.indexingDictionary( nameData.data() );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader{};
|
IdxHeader idxHeader{};
|
||||||
|
|
||||||
|
|
|
@ -335,7 +335,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile, bool hasZipFile )
|
bool indexIsOldOrBad( string const & indexFile, bool hasZipFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -443,7 +443,7 @@ private:
|
||||||
|
|
||||||
GlsDictionary::GlsDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
GlsDictionary::GlsDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
dz( 0 ),
|
dz( 0 ),
|
||||||
chunks( idx, idxHeader.chunksOffset )
|
chunks( idx, idxHeader.chunksOffset )
|
||||||
|
@ -1270,7 +1270,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
gdDebug( "Gls: Building the index for dictionary: %s\n",
|
gdDebug( "Gls: Building the index for dictionary: %s\n",
|
||||||
QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() );
|
QString::fromStdU32String( scanner.getDictionaryName() ).toUtf8().data() );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ string LsaDictionary::getName() noexcept
|
||||||
|
|
||||||
LsaDictionary::LsaDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
LsaDictionary::LsaDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() )
|
idxHeader( idx.read< IdxHeader >() )
|
||||||
{
|
{
|
||||||
// Initialize the index
|
// Initialize the index
|
||||||
|
@ -405,7 +405,7 @@ sptr< Dictionary::DataRequest > LsaDictionary::getResource( string const & name
|
||||||
return std::make_shared< Dictionary::DataRequestInstant >( false ); // No such resource
|
return std::make_shared< Dictionary::DataRequestInstant >( false ); // No such resource
|
||||||
}
|
}
|
||||||
|
|
||||||
File::Index f( getDictionaryFilenames()[ 0 ], "rb" );
|
File::Index f( getDictionaryFilenames()[ 0 ], QIODevice::ReadOnly );
|
||||||
|
|
||||||
f.seek( chain[ 0 ].articleOffset );
|
f.seek( chain[ 0 ].articleOffset );
|
||||||
Entry e( f );
|
Entry e( f );
|
||||||
|
@ -522,7 +522,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File::Index f( *i, "rb" );
|
File::Index f( *i, QIODevice::ReadOnly );
|
||||||
|
|
||||||
/// Check the signature
|
/// Check the signature
|
||||||
|
|
||||||
|
@ -547,7 +547,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
initializing.indexingDictionary( Utils::Fs::basename( *i ) );
|
initializing.indexingDictionary( Utils::Fs::basename( *i ) );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
|
|
|
@ -302,7 +302,7 @@ private:
|
||||||
|
|
||||||
MdxDictionary::MdxDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
MdxDictionary::MdxDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxFileName( indexFile ),
|
idxFileName( indexFile ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
chunks( idx, idxHeader.chunksOffset ),
|
chunks( idx, idxHeader.chunksOffset ),
|
||||||
|
@ -1307,7 +1307,7 @@ private:
|
||||||
|
|
||||||
static bool indexIsOldOrBad( vector< string > const & dictFiles, string const & indexFile )
|
static bool indexIsOldOrBad( vector< string > const & dictFiles, string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
return idx.readRecords( &header, sizeof( header ), 1 ) != 1 || header.signature != kSignature
|
return idx.readRecords( &header, sizeof( header ), 1 ) != 1 || header.signature != kSignature
|
||||||
|
@ -1385,7 +1385,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
||||||
// We write a dummy header first. At the end of the process the header
|
// We write a dummy header first. At the end of the process the header
|
||||||
|
|
|
@ -97,7 +97,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -188,10 +188,10 @@ SdictDictionary::SdictDictionary( string const & id,
|
||||||
string const & indexFile,
|
string const & indexFile,
|
||||||
vector< string > const & dictionaryFiles ):
|
vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
chunks( idx, idxHeader.chunksOffset ),
|
chunks( idx, idxHeader.chunksOffset ),
|
||||||
df( dictionaryFiles[ 0 ], "rb" )
|
df( dictionaryFiles[ 0 ], QIODevice::ReadOnly )
|
||||||
{
|
{
|
||||||
// Read dictionary name
|
// Read dictionary name
|
||||||
|
|
||||||
|
@ -689,7 +689,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
try {
|
try {
|
||||||
gdDebug( "SDict: Building the index for dictionary: %s\n", fileName.c_str() );
|
gdDebug( "SDict: Building the index for dictionary: %s\n", fileName.c_str() );
|
||||||
|
|
||||||
File::Index df( fileName, "rb" );
|
File::Index df( fileName, QIODevice::ReadOnly );
|
||||||
|
|
||||||
DCT_header dictHeader;
|
DCT_header dictHeader;
|
||||||
|
|
||||||
|
@ -722,7 +722,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
initializing.indexingDictionary( dictName );
|
initializing.indexingDictionary( dictName );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ struct RefEntry
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -702,7 +702,7 @@ private:
|
||||||
SlobDictionary::SlobDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
SlobDictionary::SlobDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idxFileName( indexFile ),
|
idxFileName( indexFile ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() )
|
idxHeader( idx.read< IdxHeader >() )
|
||||||
{
|
{
|
||||||
// Open data file
|
// Open data file
|
||||||
|
@ -1285,7 +1285,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
initializing.indexingDictionary( sf.getDictionaryName().toUtf8().constData() );
|
initializing.indexingDictionary( sf.getDictionaryName().toUtf8().constData() );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ SoundDirDictionary::SoundDirDictionary( string const & id,
|
||||||
QString const & iconFilename_ ):
|
QString const & iconFilename_ ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
name( name_ ),
|
name( name_ ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
chunks( idx, idxHeader.chunksOffset ),
|
chunks( idx, idxHeader.chunksOffset ),
|
||||||
iconFilename( iconFilename_ )
|
iconFilename( iconFilename_ )
|
||||||
|
@ -370,7 +370,7 @@ sptr< Dictionary::DataRequest > SoundDirDictionary::getResource( string const &
|
||||||
// Now try loading that file
|
// Now try loading that file
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File::Index f( fileName.toStdString(), "rb" );
|
File::Index f( fileName.toStdString(), QIODevice::ReadOnly );
|
||||||
|
|
||||||
sptr< Dictionary::DataRequestInstant > dr = std::make_shared< Dictionary::DataRequestInstant >( true );
|
sptr< Dictionary::DataRequestInstant > dr = std::make_shared< Dictionary::DataRequestInstant >( true );
|
||||||
|
|
||||||
|
@ -479,7 +479,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( Config::SoundDirs const &
|
||||||
|
|
||||||
initializing.indexingDictionary( soundDir.name.toUtf8().data() );
|
initializing.indexingDictionary( soundDir.name.toUtf8().data() );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
|
|
|
@ -76,13 +76,15 @@ DEF_EX_STR( exIncorrectOffset, "Incorrect offset encountered in file", Dictionar
|
||||||
/// Contents of an ifo file
|
/// Contents of an ifo file
|
||||||
struct Ifo
|
struct Ifo
|
||||||
{
|
{
|
||||||
string version;
|
|
||||||
string bookname;
|
string bookname;
|
||||||
uint32_t wordcount, synwordcount, idxfilesize, idxoffsetbits;
|
uint32_t wordcount = 0;
|
||||||
|
uint32_t synwordcount = 0;
|
||||||
|
uint32_t idxfilesize = 0;
|
||||||
|
uint32_t idxoffsetbits = 32;
|
||||||
string sametypesequence, dicttype, description;
|
string sametypesequence, dicttype, description;
|
||||||
string copyright, author, email, website, date;
|
string copyright, author, email, website, date;
|
||||||
|
|
||||||
explicit Ifo( File::Index & );
|
explicit Ifo( const QString & fileName );
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -116,7 +118,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -235,7 +237,7 @@ StardictDictionary::StardictDictionary( string const & id,
|
||||||
string const & indexFile,
|
string const & indexFile,
|
||||||
vector< string > const & dictionaryFiles ):
|
vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
bookName( loadString( idxHeader.bookNameSize ) ),
|
bookName( loadString( idxHeader.bookNameSize ) ),
|
||||||
sameTypeSequence( loadString( idxHeader.sameTypeSequenceSize ) ),
|
sameTypeSequence( loadString( idxHeader.sameTypeSequenceSize ) ),
|
||||||
|
@ -1085,40 +1087,36 @@ QString const & StardictDictionary::getDescription()
|
||||||
return dictionaryDescription;
|
return dictionaryDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
File::Index ifoFile( getDictionaryFilenames()[ 0 ], "r" );
|
Ifo ifo( QString::fromStdString( getDictionaryFilenames()[ 0 ] ) );
|
||||||
Ifo ifo( ifoFile );
|
|
||||||
|
|
||||||
if ( !ifo.copyright.empty() ) {
|
if ( !ifo.copyright.empty() ) {
|
||||||
QString copyright = QString::fromUtf8( ifo.copyright.c_str() ).replace( "<br>", "\n", Qt::CaseInsensitive );
|
QString copyright = QString::fromUtf8( ifo.copyright.c_str() );
|
||||||
dictionaryDescription += QObject::tr( "Copyright: %1%2" ).arg( copyright ).arg( "\n\n" );
|
dictionaryDescription += QObject::tr( "Copyright: %1%2" ).arg( copyright ).arg( "<br><br>" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !ifo.author.empty() ) {
|
if ( !ifo.author.empty() ) {
|
||||||
QString author = QString::fromUtf8( ifo.author.c_str() );
|
QString author = QString::fromUtf8( ifo.author.c_str() );
|
||||||
dictionaryDescription += QObject::tr( "Author: %1%2" ).arg( author ).arg( "\n\n" );
|
dictionaryDescription += QObject::tr( "Author: %1%2" ).arg( author ).arg( "<br><br>" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !ifo.email.empty() ) {
|
if ( !ifo.email.empty() ) {
|
||||||
QString email = QString::fromUtf8( ifo.email.c_str() );
|
QString email = QString::fromUtf8( ifo.email.c_str() );
|
||||||
dictionaryDescription += QObject::tr( "E-mail: %1%2" ).arg( email ).arg( "\n\n" );
|
dictionaryDescription += QObject::tr( "E-mail: %1%2" ).arg( email ).arg( "<br><br>" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !ifo.website.empty() ) {
|
if ( !ifo.website.empty() ) {
|
||||||
QString website = QString::fromUtf8( ifo.website.c_str() );
|
QString website = QString::fromUtf8( ifo.website.c_str() );
|
||||||
dictionaryDescription += QObject::tr( "Website: %1%2" ).arg( website ).arg( "\n\n" );
|
dictionaryDescription += QObject::tr( "Website: %1%2" ).arg( website ).arg( "<br><br>" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !ifo.date.empty() ) {
|
if ( !ifo.date.empty() ) {
|
||||||
QString date = QString::fromUtf8( ifo.date.c_str() );
|
QString date = QString::fromUtf8( ifo.date.c_str() );
|
||||||
dictionaryDescription += QObject::tr( "Date: %1%2" ).arg( date ).arg( "\n\n" );
|
dictionaryDescription += QObject::tr( "Date: %1%2" ).arg( date ).arg( "<br><br>" );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !ifo.description.empty() ) {
|
if ( !ifo.description.empty() ) {
|
||||||
QString desc = QString::fromUtf8( ifo.description.c_str() );
|
QString desc = QString::fromUtf8( ifo.description.c_str() );
|
||||||
desc.replace( "\t", "<br/>" );
|
dictionaryDescription += desc;
|
||||||
desc.replace( "\\n", "<br/>" );
|
|
||||||
desc.replace( "<br>", "<br/>", Qt::CaseInsensitive );
|
|
||||||
dictionaryDescription += Html::unescape( desc, Html::HtmlOption::Keep );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dictionaryDescription.isEmpty() ) {
|
if ( dictionaryDescription.isEmpty() ) {
|
||||||
|
@ -1457,85 +1455,77 @@ static char const * beginsWith( char const * substr, char const * str )
|
||||||
return strncmp( str, substr, len ) == 0 ? str + len : 0;
|
return strncmp( str, substr, len ) == 0 ? str + len : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ifo::Ifo( File::Index & f ):
|
Ifo::Ifo( const QString & fileName )
|
||||||
wordcount( 0 ),
|
|
||||||
synwordcount( 0 ),
|
|
||||||
idxfilesize( 0 ),
|
|
||||||
idxoffsetbits( 32 )
|
|
||||||
{
|
{
|
||||||
static string const versionEq( "version=" );
|
QFile f( fileName );
|
||||||
|
if ( !f.open( QIODevice::ReadOnly ) ) {
|
||||||
|
throw exCantReadFile( "Cannot open IFO file -> " + fileName.toStdString() );
|
||||||
|
};
|
||||||
|
|
||||||
static string const booknameEq( "bookname=" );
|
if ( !f.readLine().startsWith( "StarDict's dict ifo file" ) || !f.readLine().startsWith( "version=" ) ) {
|
||||||
|
|
||||||
//GD_DPRINTF( "%s<\n", f.gets().c_str() );
|
|
||||||
//GD_DPRINTF( "%s<\n", f.gets().c_str() );
|
|
||||||
|
|
||||||
if ( QString::fromUtf8( f.gets().c_str() ) != "StarDict's dict ifo file"
|
|
||||||
|| f.gets().compare( 0, versionEq.size(), versionEq ) ) {
|
|
||||||
throw exNotAnIfoFile();
|
throw exNotAnIfoFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Now go through the file and parse options
|
/// Now go through the file and parse options
|
||||||
|
{
|
||||||
|
while ( !f.atEnd() ) {
|
||||||
|
auto line = f.readLine();
|
||||||
|
auto option = QByteArrayView( line ).trimmed();
|
||||||
|
// Empty lines are allowed in .ifo file
|
||||||
|
|
||||||
try {
|
if ( option.isEmpty() ) {
|
||||||
char option[ 16384 ];
|
continue;
|
||||||
|
|
||||||
for ( ;; ) {
|
|
||||||
if ( !f.gets( option, sizeof( option ), true ) ) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( char const * val = beginsWith( "bookname=", option ) ) {
|
if ( char const * val = beginsWith( "bookname=", option.data() ) ) {
|
||||||
bookname = val;
|
bookname = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "wordcount=", option ) ) {
|
else if ( char const * val = beginsWith( "wordcount=", option.data() ) ) {
|
||||||
if ( sscanf( val, "%u", &wordcount ) != 1 ) {
|
if ( sscanf( val, "%u", &wordcount ) != 1 ) {
|
||||||
throw exBadFieldInIfo( option );
|
throw exBadFieldInIfo( option.data() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "synwordcount=", option ) ) {
|
else if ( char const * val = beginsWith( "synwordcount=", option.data() ) ) {
|
||||||
if ( sscanf( val, "%u", &synwordcount ) != 1 ) {
|
if ( sscanf( val, "%u", &synwordcount ) != 1 ) {
|
||||||
throw exBadFieldInIfo( option );
|
throw exBadFieldInIfo( option.data() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "idxfilesize=", option ) ) {
|
else if ( char const * val = beginsWith( "idxfilesize=", option.data() ) ) {
|
||||||
if ( sscanf( val, "%u", &idxfilesize ) != 1 ) {
|
if ( sscanf( val, "%u", &idxfilesize ) != 1 ) {
|
||||||
throw exBadFieldInIfo( option );
|
throw exBadFieldInIfo( option.data() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "idxoffsetbits=", option ) ) {
|
else if ( char const * val = beginsWith( "idxoffsetbits=", option.data() ) ) {
|
||||||
if ( sscanf( val, "%u", &idxoffsetbits ) != 1 || ( idxoffsetbits != 32 && idxoffsetbits != 64 ) ) {
|
if ( sscanf( val, "%u", &idxoffsetbits ) != 1 || ( idxoffsetbits != 32 && idxoffsetbits != 64 ) ) {
|
||||||
throw exBadFieldInIfo( option );
|
throw exBadFieldInIfo( option.data() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "sametypesequence=", option ) ) {
|
else if ( char const * val = beginsWith( "sametypesequence=", option.data() ) ) {
|
||||||
sametypesequence = val;
|
sametypesequence = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "dicttype=", option ) ) {
|
else if ( char const * val = beginsWith( "dicttype=", option.data() ) ) {
|
||||||
dicttype = val;
|
dicttype = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "description=", option ) ) {
|
else if ( char const * val = beginsWith( "description=", option.data() ) ) {
|
||||||
description = val;
|
description = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "copyright=", option ) ) {
|
else if ( char const * val = beginsWith( "copyright=", option.data() ) ) {
|
||||||
copyright = val;
|
copyright = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "author=", option ) ) {
|
else if ( char const * val = beginsWith( "author=", option.data() ) ) {
|
||||||
author = val;
|
author = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "email=", option ) ) {
|
else if ( char const * val = beginsWith( "email=", option.data() ) ) {
|
||||||
email = val;
|
email = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "website=", option ) ) {
|
else if ( char const * val = beginsWith( "website=", option.data() ) ) {
|
||||||
website = val;
|
website = val;
|
||||||
}
|
}
|
||||||
else if ( char const * val = beginsWith( "date=", option ) ) {
|
else if ( char const * val = beginsWith( "date=", option.data() ) ) {
|
||||||
date = val;
|
date = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( File::exReadError & ) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//// StardictDictionary::getResource()
|
//// StardictDictionary::getResource()
|
||||||
|
@ -1897,9 +1887,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) {
|
if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) {
|
||||||
// Building the index
|
// Building the index
|
||||||
|
|
||||||
File::Index ifoFile( fileName, "r" );
|
Ifo ifo( QString::fromStdString( fileName ) );
|
||||||
|
|
||||||
Ifo ifo( ifoFile );
|
|
||||||
|
|
||||||
gdDebug( "Stardict: Building the index for dictionary: %s\n", ifo.bookname.c_str() );
|
gdDebug( "Stardict: Building the index for dictionary: %s\n", ifo.bookname.c_str() );
|
||||||
|
|
||||||
|
@ -1930,7 +1918,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
initializing.indexingDictionary( ifo.bookname );
|
initializing.indexingDictionary( ifo.bookname );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
|
|
|
@ -37,50 +37,18 @@ bool tryPossibleZipName( std::string const & name, std::string & copyTo )
|
||||||
|
|
||||||
void loadFromFile( std::string const & filename, std::vector< char > & data )
|
void loadFromFile( std::string const & filename, std::vector< char > & data )
|
||||||
{
|
{
|
||||||
File::Index f( filename, "rb" );
|
File::Index f( filename, QIODevice::ReadOnly );
|
||||||
auto size = f.file().size(); // QFile::size() obtains size via statx on Linux
|
auto size = f.file().size(); // QFile::size() obtains size via statx on Linux
|
||||||
data.resize( size );
|
data.resize( size );
|
||||||
f.read( data.data(), size );
|
f.read( data.data(), size );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Index::open( char const * mode )
|
Index::Index( std::string_view filename, QIODevice::OpenMode mode )
|
||||||
{
|
|
||||||
QFile::OpenMode openMode = QIODevice::Text;
|
|
||||||
|
|
||||||
const char * pch = mode;
|
|
||||||
while ( *pch ) {
|
|
||||||
switch ( *pch ) {
|
|
||||||
case 'r':
|
|
||||||
openMode |= QIODevice::ReadOnly;
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
openMode |= QIODevice::WriteOnly;
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
openMode &= ~( QIODevice::ReadOnly | QIODevice::WriteOnly );
|
|
||||||
openMode |= QIODevice::ReadWrite;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
openMode |= QIODevice::Append;
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
openMode &= ~QIODevice::Text;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++pch;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !f.open( openMode ) ) {
|
|
||||||
throw exCantOpen( f.fileName().toStdString() + ": " + f.errorString().toUtf8().data() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Index::Index( std::string_view filename, char const * mode )
|
|
||||||
{
|
{
|
||||||
f.setFileName( QString::fromUtf8( filename.data(), filename.size() ) );
|
f.setFileName( QString::fromUtf8( filename.data(), filename.size() ) );
|
||||||
open( mode );
|
if ( !f.open( mode ) ) {
|
||||||
|
throw exCantOpen( ( f.fileName() + ": " + f.errorString() ).toStdString() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Index::read( void * buf, qint64 size )
|
void Index::read( void * buf, qint64 size )
|
||||||
|
|
|
@ -43,7 +43,7 @@ public:
|
||||||
QMutex lock;
|
QMutex lock;
|
||||||
|
|
||||||
// Create QFile Object and open() it.
|
// Create QFile Object and open() it.
|
||||||
Index( std::string_view filename, char const * mode );
|
Index( std::string_view filename, QIODevice::OpenMode mode );
|
||||||
|
|
||||||
/// QFile::read & QFile::write , but with exception throwing
|
/// QFile::read & QFile::write , but with exception throwing
|
||||||
void read( void * buf, qint64 size );
|
void read( void * buf, qint64 size );
|
||||||
|
@ -113,8 +113,6 @@ public:
|
||||||
~Index() noexcept;
|
~Index() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// QFile::open but with fopen-like mode settings.
|
|
||||||
void open( char const * mode );
|
|
||||||
|
|
||||||
template< typename T >
|
template< typename T >
|
||||||
void readType( T & value )
|
void readType( T & value )
|
||||||
|
|
|
@ -125,7 +125,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ private:
|
||||||
|
|
||||||
XdxfDictionary::XdxfDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
XdxfDictionary::XdxfDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() )
|
idxHeader( idx.read< IdxHeader >() )
|
||||||
{
|
{
|
||||||
// Read the dictionary name
|
// Read the dictionary name
|
||||||
|
@ -1077,7 +1077,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
|
|
||||||
//initializing.indexingDictionary( nameFromFileName( dictFiles[ 0 ] ) );
|
//initializing.indexingDictionary( nameFromFileName( dictFiles[ 0 ] ) );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
|
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
map< string, string > abrv;
|
map< string, string > abrv;
|
||||||
|
|
|
@ -93,7 +93,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
// Some supporting functions
|
// Some supporting functions
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ private:
|
||||||
|
|
||||||
ZimDictionary::ZimDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
ZimDictionary::ZimDictionary( string const & id, string const & indexFile, vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() ),
|
idxHeader( idx.read< IdxHeader >() ),
|
||||||
df( dictionaryFiles[ 0 ] )
|
df( dictionaryFiles[ 0 ] )
|
||||||
{
|
{
|
||||||
|
@ -832,7 +832,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
initializing.indexingDictionary( firstName.mid( n + 1 ).toUtf8().constData() );
|
initializing.indexingDictionary( firstName.mid( n + 1 ).toUtf8().constData() );
|
||||||
}
|
}
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
||||||
idxHeader.namePtr = 0xFFFFFFFF;
|
idxHeader.namePtr = 0xFFFFFFFF;
|
||||||
|
|
|
@ -60,7 +60,7 @@ static_assert( alignof( IdxHeader ) == 1 );
|
||||||
|
|
||||||
bool indexIsOldOrBad( string const & indexFile )
|
bool indexIsOldOrBad( string const & indexFile )
|
||||||
{
|
{
|
||||||
File::Index idx( indexFile, "rb" );
|
File::Index idx( indexFile, QIODevice::ReadOnly );
|
||||||
|
|
||||||
IdxHeader header;
|
IdxHeader header;
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ ZipSoundsDictionary::ZipSoundsDictionary( string const & id,
|
||||||
string const & indexFile,
|
string const & indexFile,
|
||||||
vector< string > const & dictionaryFiles ):
|
vector< string > const & dictionaryFiles ):
|
||||||
BtreeDictionary( id, dictionaryFiles ),
|
BtreeDictionary( id, dictionaryFiles ),
|
||||||
idx( indexFile, "rb" ),
|
idx( indexFile, QIODevice::ReadOnly ),
|
||||||
idxHeader( idx.read< IdxHeader >() )
|
idxHeader( idx.read< IdxHeader >() )
|
||||||
{
|
{
|
||||||
chunks = std::shared_ptr< ChunkedStorage::Reader >( new ChunkedStorage::Reader( idx, idxHeader.chunksOffset ) );
|
chunks = std::shared_ptr< ChunkedStorage::Reader >( new ChunkedStorage::Reader( idx, idxHeader.chunksOffset ) );
|
||||||
|
@ -405,7 +405,7 @@ vector< sptr< Dictionary::Class > > makeDictionaries( vector< string > const & f
|
||||||
if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) {
|
if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || indexIsOldOrBad( indexFile ) ) {
|
||||||
gdDebug( "Zips: Building the index for dictionary: %s\n", fileName.c_str() );
|
gdDebug( "Zips: Building the index for dictionary: %s\n", fileName.c_str() );
|
||||||
|
|
||||||
File::Index idx( indexFile, "wb" );
|
File::Index idx( indexFile, QIODevice::WriteOnly );
|
||||||
IdxHeader idxHeader;
|
IdxHeader idxHeader;
|
||||||
|
|
||||||
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
memset( &idxHeader, 0, sizeof( idxHeader ) );
|
||||||
|
|
|
@ -368,7 +368,7 @@ int main( int argc, char ** argv )
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
// TODO: Force fusion because Qt6.7's "ModernStyle"'s dark theme have problems, need to test / reconsider in future
|
// TODO: Force fusion because Qt6.7's "ModernStyle"'s dark theme have problems, need to test / reconsider in future
|
||||||
QHotkeyApplication::setStyle( QStyleFactory::create( "Fusion" ) );
|
QHotkeyApplication::setStyle( QStyleFactory::create( "WindowsVista" ) );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ void PronounceEngine::reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PronounceEngine::sendAudio( std::string dictId, QString audioLink )
|
void PronounceEngine::sendAudio( const std::string & dictId, const QString & audioLink )
|
||||||
{
|
{
|
||||||
if ( state == PronounceState::OCCUPIED ) {
|
if ( state == PronounceState::OCCUPIED ) {
|
||||||
return;
|
return;
|
||||||
|
@ -29,7 +29,7 @@ void PronounceEngine::sendAudio( std::string dictId, QString audioLink )
|
||||||
|
|
||||||
QMutexLocker _( &mutex );
|
QMutexLocker _( &mutex );
|
||||||
|
|
||||||
dictAudioMap.operator[]( dictId ).push_back( audioLink );
|
dictAudioMap[ dictId ].append( audioLink );
|
||||||
}
|
}
|
||||||
|
|
||||||
void PronounceEngine::finishDictionary( std::string dictId )
|
void PronounceEngine::finishDictionary( std::string dictId )
|
||||||
|
|
|
@ -21,7 +21,7 @@ class PronounceEngine: public QObject
|
||||||
public:
|
public:
|
||||||
explicit PronounceEngine( QObject * parent = nullptr );
|
explicit PronounceEngine( QObject * parent = nullptr );
|
||||||
void reset();
|
void reset();
|
||||||
void sendAudio( std::string dictId, QString audioLink );
|
void sendAudio( const std::string & dictId, const QString & audioLink );
|
||||||
void finishDictionary( std::string dictId );
|
void finishDictionary( std::string dictId );
|
||||||
signals:
|
signals:
|
||||||
void emitAudio( QString audioLink );
|
void emitAudio( QString audioLink );
|
||||||
|
|
|
@ -1356,8 +1356,10 @@ void MainWindow::updateAppearances( QString const & addonStyle,
|
||||||
darkPalette.setColor( QPalette::Disabled, QPalette::HighlightedText, disabledColor );
|
darkPalette.setColor( QPalette::Disabled, QPalette::HighlightedText, disabledColor );
|
||||||
|
|
||||||
qApp->setPalette( darkPalette );
|
qApp->setPalette( darkPalette );
|
||||||
|
qApp->setStyle( "Fusion" );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
qApp->setStyle( "WindowsVista" );
|
||||||
qApp->setPalette( QPalette() );
|
qApp->setPalette( QPalette() );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -185,6 +185,7 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
|
||||||
ui.doubleClickTranslates->setChecked( p.doubleClickTranslates );
|
ui.doubleClickTranslates->setChecked( p.doubleClickTranslates );
|
||||||
ui.selectBySingleClick->setChecked( p.selectWordBySingleClick );
|
ui.selectBySingleClick->setChecked( p.selectWordBySingleClick );
|
||||||
ui.autoScrollToTargetArticle->setChecked( p.autoScrollToTargetArticle );
|
ui.autoScrollToTargetArticle->setChecked( p.autoScrollToTargetArticle );
|
||||||
|
ui.targetArticleAtFirst->setChecked( p.targetArticleAtFirst );
|
||||||
ui.escKeyHidesMainWindow->setChecked( p.escKeyHidesMainWindow );
|
ui.escKeyHidesMainWindow->setChecked( p.escKeyHidesMainWindow );
|
||||||
|
|
||||||
ui.darkMode->addItem( tr( "On" ), QVariant::fromValue( Config::Dark::On ) );
|
ui.darkMode->addItem( tr( "On" ), QVariant::fromValue( Config::Dark::On ) );
|
||||||
|
@ -441,6 +442,7 @@ Config::Preferences Preferences::getPreferences()
|
||||||
p.doubleClickTranslates = ui.doubleClickTranslates->isChecked();
|
p.doubleClickTranslates = ui.doubleClickTranslates->isChecked();
|
||||||
p.selectWordBySingleClick = ui.selectBySingleClick->isChecked();
|
p.selectWordBySingleClick = ui.selectBySingleClick->isChecked();
|
||||||
p.autoScrollToTargetArticle = ui.autoScrollToTargetArticle->isChecked();
|
p.autoScrollToTargetArticle = ui.autoScrollToTargetArticle->isChecked();
|
||||||
|
p.targetArticleAtFirst = ui.targetArticleAtFirst->isChecked();
|
||||||
p.escKeyHidesMainWindow = ui.escKeyHidesMainWindow->isChecked();
|
p.escKeyHidesMainWindow = ui.escKeyHidesMainWindow->isChecked();
|
||||||
|
|
||||||
p.darkMode = ui.darkMode->currentData().value< Config::Dark >();
|
p.darkMode = ui.darkMode->currentData().value< Config::Dark >();
|
||||||
|
|
|
@ -169,6 +169,16 @@ however, the article from the topmost dictionary is shown.</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QCheckBox" name="targetArticleAtFirst">
|
||||||
|
<property name="text">
|
||||||
|
<string>Place the target article at the first place.</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QGroupBox" name="enableTrayIcon">
|
<widget class="QGroupBox" name="enableTrayIcon">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
|
Loading…
Reference in a new issue