Skip to content

Instantly share code, notes, and snippets.

@ma8ma
Last active May 30, 2019 10:46
Show Gist options
  • Save ma8ma/00ae0bb80c505539c68af01c758908fe to your computer and use it in GitHub Desktop.
Save ma8ma/00ae0bb80c505539c68af01c758908fe to your computer and use it in GitHub Desktop.
JDim バージョン0.1.0対応 玉葱パッチ
これは2(5)ちゃんねるブラウザJDimに機能を追加するパッチです。
URL: https://github.com/JDimproved/JDim
使用方法
1. masterブランチ(コミットハッシュ:a279663014)にこのパッチを当てます
2. JDimをビルドします
3. JDimを起動します
ライセンス
GNU General Public License, version 2
このパッチの一切の権利を「JDimproved project」に譲渡します。
その他
予期しない問題が起こることがあるかもしれません。
本パッチ作者はソフトウェアの正常動作を保証しません。
以上、ここからオリジナルの説明文
このファイルの簡単な説明
これはjdを5ch.netに読み書き出来るようにするパッチです。
使用方法
1. このパッチを当てます
ex) xzcat jd-2.8.9-150226-aYYMMDD.patch.xz | patch -p1
2. jdをビルドします
3. jdを起動します
4. 設定(C)→about:config 高度な設定(C)を開きます
5. ■ネットワークの辺りをテキトーに設定します
6. jdを終了します
7. jdを再び起動します
8-1. APIを使う場合はファイル(F)→5chにログイン(L)を実行します
8-2. read.cgiを使う場合は設定(C)→一般(G)→5chでスレ取得にread.cgiを使う
ライセンス等
GNU General Public License, version 2
このパッチの一切の権利を「JD Project」に譲渡します。
その他
予期しない問題が起こることがあるかもしれません。
本パッチ作者はソフトウェアの正常動作を保証しません。
以上
diff --git a/configure.ac b/configure.ac
index 1700c807..0222855e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ dnl JDim用 configure.ac
dnl
AC_PREREQ(2.50)
AC_INIT(jdim, 1.0)
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE([1.13 -Wno-portability])
AC_CONFIG_HEADERS(config.h)
AC_ISC_POSIX
@@ -32,30 +32,22 @@ dnl OSを判定してOS別の設定
dnl
case "${host_os}" in
freebsd*)
- echo "os = freebsd"
AC_DEFINE(USE_MKTIME, , "use mktime")
;;
solaris*)
- echo "os = solaris"
AC_DEFINE(NO_TIMEGM, , "no timegm")
;;
mingw*)
- echo "os = ${host_os}"
AC_DEFINE(USE_MKTIME, , "use mktime")
;;
darwin*)
- echo "os = ${host_os}"
- AC_DEFUN([AM_ICONV], [])
AC_DEFINE(USE_MKTIME, , "use mktime")
;;
dnl linux*|gnu*|*-gnu
*)
- echo "os = ${host_os}"
- AC_DEFUN([AM_ICONV], [])
;;
esac
-AM_ICONV
dnl ---------------------------------------------------
@@ -110,8 +102,6 @@ AC_SUBST(GTKMM_LIBS)
dnl
dnl crypt
dnl
-
-echo "use crypt"
AC_CHECK_HEADERS([crypt.h])
AC_CHECK_LIB(crypt,crypt)
@@ -119,12 +109,27 @@ AC_CHECK_LIB(crypt,crypt)
dnl
dnl zlib
dnl
-
-echo "use zlib"
AC_CHECK_HEADERS([zlib.h])
AC_CHECK_LIB(z,inflate)
+dnl
+dnl iconv
+dnl
+found_iconv=no
+AC_CHECK_FUNC(iconv_open, [found_iconv=yes])
+if test $found_iconv = "no"; then
+ AC_CHECK_LIB(iconv, libiconv_open, [found_iconv=yes])
+
+ if test $found_iconv = "no"; then
+ AC_CHECK_LIB(iconv, iconv_open, ,AC_MSG_ERROR([iconv implementation not found]))
+ fi
+
+ ICONV_LIBS="-liconv"
+ AC_SUBST(ICONV_LIBS)
+fi
+
+
dnl
dnl packages dependent on platform
dnl
@@ -137,22 +142,14 @@ case "${host_os}" in
dnl not available uname on windows
dnl
- echo "use winsock2"
AC_CHECK_HEADERS([winsock2.h])
AC_CHECK_LIB(ws2_32,_head_libws2_32_a)
- echo "use regex2"
- AC_CHECK_HEADERS([regex.h])
- AC_CHECK_LIB(regex,regexec)
+ AC_CHECK_HEADERS([wspiapi.h])
- echo "use iconv"
- AC_CHECK_HEADERS([iconv.h])
- AC_CHECK_LIB(iconv,_head_libiconv_a)
-
- echo "use windows resources"
AC_CHECK_TOOL([WINDRES], [windres], [windres])
AC_SUBST(WINDRES)
- AC_DEFINE(USE_WINDRES, , "use windres")
+ AC_DEFINE(USE_WINDRES, ,[use windres])
use_windres="yes"
;;
*)
@@ -160,10 +157,8 @@ case "${host_os}" in
dnl any other POSIX systems
dnl
- echo "use uname"
AC_CHECK_HEADERS([sys/utsname.h])
- echo "use socket"
AC_CHECK_HEADERS([socket.h])
AC_CHECK_LIB(socket,socket)
;;
@@ -197,10 +192,8 @@ use_xsmp=no
use_gnomeui=no
AC_ARG_WITH(sessionlib,
-[
- --with-sessionlib[[=xsmp/gnomeui/no]]
- use session control library [[default=xsmp]]
-],
+AC_HELP_STRING([--with-sessionlib@<:@=xsmp|gnomeui|no@:>@],
+ [use session control library @<:@default=xsmp@:>@]),
[case "${withval}" in
xsmp)
use_xsmp=yes
@@ -253,10 +246,9 @@ if test x"$use_xsmp" = "xyes" ; then
fi
if test -n "$LIBSM_CFLAGS" -a -n "$LIBSM_LIBS" ; then
- echo "use XSMP"
+ AC_DEFINE(USE_XSMP, ,[use xsmp])
AC_SUBST(LIBSM_CFLAGS)
AC_SUBST(LIBSM_LIBS)
- CXXFLAGS="$CXXFLAGS -DUSE_XSMP"
fi
fi
@@ -267,43 +259,147 @@ if test x"$use_gnomeui" = "xyes" ; then
PKG_CHECK_MODULES(GNOMEUI, [libgnomeui-2.0 >= 2.0] )
- echo "use GNOMEUI"
+ AC_DEFINE(USE_GNOMEUI, ,[use gnomeui])
AC_SUBST(GNOMEUI_CFLAGS)
AC_SUBST(GNOMEUI_LIBS)
- CXXFLAGS="$CXXFLAGS -DUSE_GNOMEUI"
fi
dnl
-dnl SSL
+dnl 正規表現ライブラリ
+dnl
+use_regex=no
+use_pcre=no
+use_onig=no
+
+AC_ARG_WITH(regex,
+AC_HELP_STRING([--with-regex@<:@=posix|pcre|oniguruma|glib@:>@],
+ [use regular expression library @<:@default=posix@:>@]),
+[case "${withval}" in
+ pcre)
+ use_pcre=yes
+ ;;
+ oniguruma)
+ use_onig=yes
+ ;;
+ glib|no)
+ use_regex=no
+ ;;
+ *)
+ use_regex=yes
+ ;;
+esac],use_regex=yes)
+
+AC_MSG_CHECKING([regular expression library])
+
+dnl
+dnl checking posix regex
+dnl
+if test x"$use_regex" = "xyes" ; then
+ AC_MSG_RESULT([posix])
+ AC_CHECK_HEADERS([regex.h], ,[AC_MSG_ERROR([regex.h not found])])
+ AC_CHECK_LIB([regex],[regexec])
+fi
+
+
+dnl
+dnl checking PCRE
+dnl
+if test x"$use_pcre" = "xyes" ; then
+ AC_MSG_RESULT([pcre])
+ PKG_CHECK_MODULES(PCRE, [libpcre >= 6.5] )
+ AC_SUBST(PCRE_CFLAGS)
+ AC_SUBST(PCRE_LIBS)
+ AC_CHECK_HEADERS([pcreposix.h], ,[AC_MSG_ERROR([pcreposix.h not found])])
+ AC_CHECK_LIB([pcreposix],[regexec], ,[AC_MSG_ERROR([libpcreposix.a not found])])
+fi
+
+
+dnl
+dnl checking oniguruma
+dnl
+AS_IF(
+ [test "x$use_onig" = xyes],
+ [AC_MSG_RESULT([oniguruma])
+ PKG_CHECK_MODULES(ONIG, [oniguruma])
+ AC_SUBST(ONIG_CFLAGS)
+ AC_SUBST(ONIG_LIBS)
+ AC_CHECK_HEADERS([onigposix.h], , [AC_MSG_ERROR([onigposix.h not found])])
+ AC_CHECK_LIB([onig], [regexec], , [AC_MSG_ERROR([libonig.a not found])])]
+)
+
+
+dnl
+dnl glib regex
+dnl
+if test x"$use_regex" != "xyes" -a x"$use_pcre" != "xyes" -a x"$use_onig" != "xyes" ; then
+ AC_MSG_RESULT([glib])
+ PKG_CHECK_MODULES(GLIB,[glib-2.0 >= 2.14.0], ,[regular expression library not found])
+fi
+
+
+dnl
+dnl TLS
dnl
-use_gnutls=yes
+use_gnutls=no
+use_openssl=no
+use_nss=no
-AC_ARG_WITH(openssl,[ --with-openssl (use openssl)],
- [ if test "$withval" != "no" ;then
- use_gnutls=no
- fi ])
+AC_ARG_WITH(tls,
+AC_HELP_STRING([--with-tls@<:@=gnutls|openssl|nss@:>@],
+ [use TLS library @<:@default=gnutls@:>@]),
+[case "${withval}" in
+ gnutls)
+ use_gnutls=yes
+ ;;
+ openssl)
+ use_openssl=yes
+ ;;
+ nss)
+ use_nss=yes
+ ;;
+esac],use_gnutls=yes)
-case "${use_gnutls}" in
- yes)
- echo "use gnutls"
- PKG_CHECK_MODULES(GNUTLS, [gnutls >= 1.2], [echo "gnutls >= 1.2"])
- AC_DEFINE(USE_GNUTLS, , "use gnutls")
- AC_CHECK_HEADERS([gcrypt.h])
- AC_CHECK_LIB(gcrypt, gcry_md_hash_buffer, [], [AC_MSG_ERROR([gcrypt not found])])
- AC_SUBST(GNUTLS_CFLAGS)
- AC_SUBST(GNUTLS_LIBS)
- ;;
- *)
- echo "use openssl"
- PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9] )
- AC_DEFINE(USE_OPENSSL, , "use openssl")
- AC_SUBST(OPENSSL_CFLAGS)
- AC_SUBST(OPENSSL_LIBS)
- ;;
-esac
+dnl
+dnl checking gnutls
+dnl
+if test x"$use_gnutls" = "xyes" ; then
+ PKG_CHECK_MODULES(GNUTLS, [gnutls >= 2.10.0], ,[AC_MSG_ERROR([gnitls >= 2.10.0 required])])
+ AC_DEFINE(USE_GNUTLS, ,[use gnutls])
+ AC_SUBST(GNUTLS_CFLAGS)
+ AC_SUBST(GNUTLS_LIBS)
+fi
+
+dnl
+dnl checking openssl
+dnl
+if test x"$use_openssl" = "xyes" ; then
+ PKG_CHECK_MODULES(OPENSSL, [openssl >= 0.9.7], ,[AC_MSG_ERROR([openssl >= 0.9.7 required])])
+ AC_DEFINE(USE_OPENSSL, ,[use openssl])
+ AC_SUBST(OPENSSL_CFLAGS)
+ AC_SUBST(OPENSSL_LIBS)
+fi
+
+
+dnl
+dnl checking nss
+dnl
+if test x"$use_nss" = "xyes" ; then
+ PKG_CHECK_MODULES(NSS, [nss >= 1.0], ,[AC_MSG_ERROR([nss >= 1.0 required])])
+ AC_DEFINE(USE_NSS, ,[use nss])
+ AC_SUBST(NSS_CFLAGS)
+ AC_SUBST(NSS_LIBS)
+fi
+
+
+AC_ARG_WITH(rootcert,
+AC_HELP_STRING([--with-rootcert=PATH],[specifiy the path of root certification file]),
+ [ if test x"$withval" != "xno" ;then
+ echo "root cert = $withval"
+ AC_DEFINE_UNQUOTED(DEFAULT_CAFILE, "$withval",[root cert])
+ fi ])
dnl
@@ -312,198 +408,108 @@ dnl
use_gprof=no
-AC_ARG_ENABLE(gprof,[ --enable-gprof (enable gprof)],
- [ if test "$enable_gprof" = "yes"; then
- echo "use gprof"
- CXXFLAGS="$CXXFLAGS -pg"
- use_gprof=yes
- fi ])
+AC_ARG_ENABLE(gprof,
+AC_HELP_STRING([--enable-gprof],[enable gprof]),
+ [ if test x"$enable_gprof" != "xno"; then
+ CXXFLAGS="$CXXFLAGS -pg"
+ use_gprof=yes
+ fi ])
dnl
dnl checking migemo
dnl
-AC_ARG_WITH(migemo,[ --with-migemo (enable migemo search)],
- [ if test "$withval" != "no" ;then
- echo "use migemo"
- AC_CHECK_HEADERS([migemo.h])
- AC_CHECK_LIB(migemo,migemo_open)
- fi ])
+AC_ARG_WITH(migemo,
+AC_HELP_STRING([--with-migemo],[enable migemo search]),
+ [ if test x"$withval" != "xno" ;then
+ AC_CHECK_HEADERS([migemo.h])
+ AC_CHECK_LIB(migemo,migemo_open)
+ fi ])
-AC_ARG_WITH(migemodict,[ --with-migemodict (specifiy the path of migemo dictionary)],
- [ if test "$withval" ;then
- echo "migemodict = $withval"
- AC_DEFINE_UNQUOTED(MIGEMODICT, "$withval" , "migemodict")
- fi ])
+AC_ARG_WITH(migemodict,
+AC_HELP_STRING([--with-migemodict=PATH],[specifiy the path of migemo dictionary]),
+ [ if test "$withval" ;then
+ AC_DEFINE_UNQUOTED(MIGEMODICT,"$withval",[migemodict])
+ fi ])
dnl
dnl checking xdg-open
dnl
-AC_ARG_WITH(xdgopen,[ --with-xdgopen (use xdg-open as default browser)],
- [ if test "$withval" ;then
- echo "use xdg-open"
- AC_DEFINE(XDGOPEN, , "use xdg-open")
- fi ])
+AC_ARG_WITH(xdgopen,
+AC_HELP_STRING([--with-xdgopen],[use xdg-open as default browser]),
+ [ if test x"$withval" != "xno" ;then
+ AC_DEFINE(XDGOPEN, ,[use xdg-open])
+ fi ])
dnl
dnl checking alsa
dnl
case "${host_os}" in
- linux*|*linux)
- AC_ARG_WITH(alsa,[ --with-alsa (enable alsa)],
- [ if test "$withval" != "no" ;then
- echo "use alsa"
- PKG_CHECK_MODULES(ALSA, [alsa >= 1.0] )
- AC_DEFINE(USE_ALSA, , "use alsa")
- AC_SUBST(ALSA_CFLAGS)
- AC_SUBST(ALSA_LIBS)
- fi ])
+ linux*|*linux)
+ AC_ARG_WITH(alsa,
+ AC_HELP_STRING([--with-alsa],[enable alsa]),
+ [ if test x"$withval" != "xno" ;then
+ PKG_CHECK_MODULES(ALSA, [alsa >= 1.0] )
+ AC_DEFINE(USE_ALSA, ,[use alsa])
+ AC_SUBST(ALSA_CFLAGS)
+ AC_SUBST(ALSA_LIBS)
+ fi ])
;;
esac
dnl
-dnl checking oniguruma
+dnl thread
dnl
-AC_MSG_CHECKING(for --with-oniguruma)
-AC_ARG_WITH(oniguruma,
- AS_HELP_STRING([--with-oniguruma], [enable oniguruma regular expressions library]),
- [with_oniguruma="$withval"],
- [with_oniguruma=no])
-AC_MSG_RESULT($with_oniguruma)
+use_gthread=no
+use_stdthread=no
+
+AC_ARG_WITH(thread,
+AC_HELP_STRING([--with-thread@<:@=posix|glib|std@:>@],
+ [use thread library @<:@default=posix@:>@]),
+[case "${withval}" in
+ glib)
+ use_gthread=yes
+ ;;
+ std)
+ use_stdthread=yes
+ ;;
+esac],[])
AS_IF(
- [test "x$with_oniguruma" = xyes],
- [PKG_CHECK_MODULES(ONIG, [oniguruma])
- AC_CHECK_HEADER([onigposix.h], , [AC_MSG_ERROR([onigposix.h not found])])
- AC_CHECK_LIB([onig], [regexec], , [AC_MSG_ERROR([libonig.a not found])])
- AC_DEFINE(USE_ONIG, , [use oniguruma regular expressions library])
- AC_SUBST(ONIG_CFLAGS)
- AC_SUBST(ONIG_LIBS)]
-)
-
-
-dnl
-dnl checking PCRE
-dnl
-AC_ARG_WITH(pcre,[ --with-pcre (enable PCRE)],
- [ if test "$withval" != "no" ;then
- echo "use PCRE"
- PKG_CHECK_MODULES(PCRE, [libpcre >= 6.5] )
- AC_DEFINE(USE_PCRE, , "use PCRE")
- AC_SUBST(PCRE_CFLAGS)
- AC_SUBST(PCRE_LIBS)
- AC_CHECK_HEADERS([pcreposix.h])
- AC_CHECK_LIB(pcreposix,regexec)
- fi ])
-
-
-dnl
-dnl checking gthread
-dnl
-AC_MSG_CHECKING(for --with-gthread)
-AC_ARG_WITH(gthread,
- AS_HELP_STRING([--with-gthread],
- [use gthread instead of pthread [default=no]]),
- [with_gthread="$withval"],
- [with_gthread=no])
-AC_MSG_RESULT($with_gthread)
-
-
-dnl
-dnl checking std::thread
-dnl
-AC_MSG_CHECKING(for --with-stdthread)
-AC_ARG_WITH(stdthread,
- AS_HELP_STRING([--with-stdthread],
- [use std::thread instead of pthread [default=no]]),
- [with_stdthread="$withval"],
- [with_stdthread=no])
-AC_MSG_RESULT($with_stdthread)
-
-
-AS_IF(
- [test "x$with_gthread" = xyes -a "x$with_stdthread" = xyes],
- [AC_MSG_ERROR([cannot configure both gthread and stdthread.])],
- [test "x$with_gthread" = xyes],
- [AC_MSG_WARN([--with-gthread is deprecated. Use --with-stdthread instead.])
- AC_DEFINE(USE_GTHREAD, , [use gthread instead of pthread])],
- [test "x$with_stdthread" = xyes],
+ [test "x$use_gthread" = xyes],
+ [AC_MSG_WARN([--with-thread=glib is deprecated. Use --with-thread=std instead.])
+ AC_DEFINE(USE_GTHREAD, , [Use gthread instead of pthread])],
+ [test "x$use_stdthread" = xyes],
[AC_DEFINE(WITH_STD_THREAD, 1, [Use std::thread instead of pthread])]
)
+dnl
+dnl checking pangolayout
+dnl
+AC_ARG_WITH(pangolayout,
+AC_HELP_STRING([--with-pangolayout],[use pangolayout]),
+ [ if test x"$withval" != "xno" ;then
+ AC_DEFINE(USE_PANGOLAYOUT, ,[use pangolayout])
+ fi ])
+
+
dnl
dnl CPU別の最適化オプション
dnl
-if test "$use_gprof" = "no"; then
-
- dnl
- dnl checking native (gcc >= 4.2 x86 & x86_64)
- dnl
- AC_ARG_WITH(native,[ --with-native (use native)],
- [ if test "$withval" != "no"; then
- echo "use native"
+if test x"$use_gprof" = "xno"; then
+ dnl
+ dnl checking native (gcc >= 4.2 x86 & x86_64)
+ dnl
+ AC_ARG_ENABLE(native,
+ AC_HELP_STRING([--enable-native],[enable optimize for native processor]),
+ [ if test x"$enableval" != "xno"; then
CXXFLAGS="$CXXFLAGS -march=native"
fi ])
-
- dnl
- dnl checking core2duo
- dnl
- AC_ARG_WITH(core2duo,[ --with-core2duo (use core2duo)],
- [ if test "$withval" != "no"; then
- echo "use core2duo"
- CXXFLAGS="$CXXFLAGS -march=pentium-m -msse3"
- fi ])
-
- dnl
- dnl checking athlon64
- dnl
- AC_ARG_WITH(athlon64,[ --with-athlon64 (use athlon64)],
- [ if test "$withval" != "no"; then
- echo "use athlon64"
- CXXFLAGS="$CXXFLAGS -march=athlon64"
- fi ])
-
- dnl
- dnl checking atom
- dnl
- AC_ARG_WITH(atom,[ --with-atom (use atom)],
- [ if test "$withval" != "no"; then
- echo "use atom"
- CXXFLAGS="$CXXFLAGS -march=prescott"
- fi ])
-
- dnl
- dnl checking ppc7400
- dnl
- AC_ARG_WITH(ppc7400,[ --with-ppc7400 (use PowerPC7400)],
- [ if test "$withval" != "no"; then
- echo "use ppc7400"
- CXXFLAGS="$CXXFLAGS -mcpu=7400 -maltivec -mabi=altivec"
- fi ])
-
- dnl
- dnl checking ppc7450
- dnl
- AC_ARG_WITH(ppc7450,[ --with-ppc7450 (use PowerPC7450)],
- [ if test "$withval" != "no"; then
- echo "use ppc7450"
- CXXFLAGS="$CXXFLAGS -mcpu=7450 -maltivec -mabi=altivec"
- fi ])
fi
-dnl
-dnl checking pangolayout
-dnl
-AC_ARG_WITH(pangolayout,[ --with-pangolayout (use pangolayout)],
- [ if test "$withval" != "no" ;then
- echo "use pango_layout for drawing"
- CXXFLAGS="$CXXFLAGS -DUSE_PANGOLAYOUT"
- fi ])
-
-
AC_OUTPUT(Makefile src/Makefile src/skeleton/Makefile src/jdlib/Makefile src/dbtree/Makefile src/dbimg/Makefile src/bbslist/Makefile src/board/Makefile src/article/Makefile src/image/Makefile src/message/Makefile src/history/Makefile src/config/Makefile src/icons/Makefile src/sound/Makefile src/xml/Makefile src/control/Makefile )
diff --git a/src/Makefile.am b/src/Makefile.am
index 739ff8e8..67838c82 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@ jdim_LDADD = \
./sound/libsound.a \
./xml/libxml.a \
./control/libcontrol.a \
- @LIBS@ @GTKMM_LIBS@ @GTHREAD_LIBS@ @GNUTLS_LIBS@ @OPENSSL_LIBS@ @GNOMEUI_LIBS@ @LIBSM_LIBS@ @ALSA_LIBS@ @ONIG_LIBS@ @X11_LIBS@
+ @GNOMEUI_LIBS@ @GTKMM_LIBS@ @GNUTLS_LIBS@ @OPENSSL_LIBS@ @NSS_LIBS@ @LIBSM_LIBS@ @ALSA_LIBS@ @ONIG_LIBS@ @X11_LIBS@ @ICONV_LIBS@
jdim_SOURCES = \
@@ -33,6 +33,7 @@ jdim_SOURCES = \
dndmanager.cpp \
usrcmdmanager.cpp \
linkfiltermanager.cpp \
+ replacestrmanager.cpp \
urlreplacemanager.cpp \
compmanager.cpp \
searchmanager.cpp \
@@ -63,6 +64,7 @@ jdim_SOURCES = \
fontcolorpref.cpp \
usrcmdpref.cpp \
linkfilterpref.cpp \
+ replacestrpref.cpp \
livepref.cpp \
openurldiag.cpp \
\
@@ -88,6 +90,7 @@ noinst_HEADERS = \
dndmanager.h \
usrcmdmanager.h \
linkfiltermanager.h \
+ replacestrmanager.h \
urlreplacemanager.h \
compmanager.h \
searchmanager.h \
@@ -128,6 +131,7 @@ noinst_HEADERS = \
fontcolorpref.h \
usrcmdpref.h \
linkfilterpref.h \
+ replacestrpref.h \
livepref.h \
openurldiag.h \
\
@@ -139,7 +143,7 @@ noinst_HEADERS = \
type.h
-AM_CXXFLAGS = @GTKMM_CFLAGS@ @GTHREAD_CFLAGS@ @GNUTLS_CFLAGS@ @OPENSSL_CFLAGS@ @GNOMEUI_CFLAGS@ @LIBSM_CFLAGS@
+AM_CXXFLAGS = @GTKMM_CFLAGS@ @GNUTLS_CFLAGS@ @OPENSSL_CFLAGS@ @NSS_CFLAGS@ @GNOMEUI_CFLAGS@ @LIBSM_CFLAGS@
jd_windres.o: jdversion.h
diff --git a/src/article/articleadmin.cpp b/src/article/articleadmin.cpp
index 96de558a..3d6280ad 100644
--- a/src/article/articleadmin.cpp
+++ b/src/article/articleadmin.cpp
@@ -765,7 +765,7 @@ void ArticleAdmin::slot_drag_data_get( Gtk::SelectionData& selection_data, const
CORE::DATA_INFO info;
info.type = TYPE_THREAD;
info.url = DBTREE::url_readcgi( url, 0, 0 );
- info.name = DBTREE::article_subject( info.url );
+ info.name = MISC::to_plain( DBTREE::article_modified_subject( info.url ) );
info.path = Gtk::TreePath( "0" ).to_string();
if( info.url.empty() ) return;
diff --git a/src/article/articleview.cpp b/src/article/articleview.cpp
index ec85801a..f85baf16 100644
--- a/src/article/articleview.cpp
+++ b/src/article/articleview.cpp
@@ -86,7 +86,7 @@ ArticleViewMain::~ArticleViewMain()
// 閉じたタブ履歴更新
HISTORY::append_history( URL_HISTCLOSEVIEW,
DBTREE::url_dat( get_url() ),
- DBTREE::article_subject( get_url() ), TYPE_THREAD );
+ DBTREE::article_modified_subject( get_url() ), TYPE_THREAD );
CORE::core_set_command( "close_message" ,url_article() );
@@ -182,7 +182,7 @@ bool ArticleViewMain::is_loading() const
// 更新した
-bool ArticleViewMain::is_updated()
+bool ArticleViewMain::is_updated() const
{
#ifdef _DEBUG
@@ -194,7 +194,7 @@ bool ArticleViewMain::is_updated()
// 更新チェックして更新可能か
-bool ArticleViewMain::is_check_update()
+bool ArticleViewMain::is_check_update() const
{
#ifdef _DEBUG
std::cout << "ArticleViewMain::is_check_update " << url_article() << " " << ( get_article()->get_status() & STATUS_UPDATE ) << std::endl;
@@ -204,13 +204,13 @@ bool ArticleViewMain::is_check_update()
}
// 古いデータか
-bool ArticleViewMain::is_old()
+bool ArticleViewMain::is_old() const
{
return ( get_article()->get_status() & STATUS_OLD );
}
// 壊れているか
-bool ArticleViewMain::is_broken()
+bool ArticleViewMain::is_broken() const
{
return ( get_article()->get_status() & STATUS_BROKEN );
}
@@ -477,20 +477,20 @@ void ArticleViewMain::update_finish()
else if( is_old() ) str_tablabel = "[ DAT落ち ] ";
else if( is_overflow() ) str_tablabel = "[ レス数が最大表示可能数以上です ] ";
- if( get_label().empty() || ! str_tablabel.empty() ) set_label( str_tablabel + DBTREE::article_subject( url_article() ) );
+ set_tooltip_label( str_tablabel + MISC::to_markup( DBTREE::article_subject( url_article() ) ) );
+ const std::string& subject = DBTREE::article_modified_subject( url_article() );
+ set_label( str_tablabel + MISC::to_markup( subject ), true );
ARTICLE::get_admin()->set_command( "redraw_toolbar" );
// タブのラベルセット
- std::string str_label = DBTREE::article_subject( url_article() );
- if( str_label.empty() ) str_label = "???";
- ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), str_label );
+ ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), subject.empty() ? "???" : subject );
// タブのアイコン状態を更新
ARTICLE::get_admin()->set_command( "toggle_icon", get_url() );
#ifdef _DEBUG
const int code = DBTREE::article_code( url_article() );
- std::cout << "ArticleViewMain::update_finish " << str_label << " code = " << code << std::endl;;
+ std::cout << "ArticleViewMain::update_finish " << str_tablabel << " code = " << code << std::endl;;
#endif
// 新着セパレータを消す
@@ -506,7 +506,7 @@ void ArticleViewMain::update_finish()
ARTICLE::get_admin()->set_command( "set_status_color", get_url(), get_color(), force );
// タイトルセット
- set_title( DBTREE::article_subject( url_article() ) );
+ set_title( MISC::to_plain( subject ) );
ARTICLE::get_admin()->set_command( "set_title", get_url(), get_title() );
drawarea()->set_enable_draw( true );
@@ -594,7 +594,7 @@ void ArticleViewMain::update_finish()
// 履歴に登録
if( m_set_history ) HISTORY::append_history( URL_HISTTHREADVIEW,
DBTREE::url_dat( get_url() ),
- DBTREE::article_subject( get_url() ), TYPE_THREAD );
+ subject, TYPE_THREAD );
if( m_show_instdialog ) show_instruct_diag();
@@ -667,10 +667,10 @@ void ArticleViewMain::show_instruct_diag()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewMain::relayout()
+void ArticleViewMain::relayout( const bool completely )
{
#ifdef _DEBUG
- std::cout << "ArticleViewMain::relayout " << DBTREE::article_subject( url_article() ) << std::endl;;
+ std::cout << "ArticleViewMain::relayout " << url_article() << std::endl;;
#endif
hide_popup( true );
@@ -679,6 +679,8 @@ void ArticleViewMain::relayout()
int num_reserve = drawarea()->get_goto_num_reserve();
int separator_new = drawarea()->get_separator_new();
+ if( completely ) DBTREE::article_clear_nodetree( url_article() );
+
drawarea()->clear_screen();
drawarea()->set_separator_new( separator_new );
drawarea()->append_res( 1, get_article()->get_number_load() );
diff --git a/src/article/articleview.h b/src/article/articleview.h
index f21b2a36..5916b443 100644
--- a/src/article/articleview.h
+++ b/src/article/articleview.h
@@ -46,16 +46,16 @@ namespace ARTICLE
void save_session() override;
bool is_loading() const override;
- bool is_updated() override;
- bool is_check_update() override;
- bool is_old() override;
- bool is_broken() override;
+ bool is_updated() const override;
+ bool is_check_update() const override;
+ bool is_old() const override;
+ bool is_broken() const override;
bool is_overflow() const noexcept override;
void show_view() override;
void update_view() override;
void update_finish() override;
- void relayout() override;
+ void relayout( const bool completely = false ) override;
protected:
diff --git a/src/article/articleviewbase.cpp b/src/article/articleviewbase.cpp
index 09a4afa2..9e30395a 100644
--- a/src/article/articleviewbase.cpp
+++ b/src/article/articleviewbase.cpp
@@ -120,26 +120,12 @@ SKELETON::Admin* ArticleViewBase::get_admin()
//
// メインウィンドウのURLバーなどの表示用にも使う
//
-std::string ArticleViewBase::url_for_copy()
+std::string ArticleViewBase::url_for_copy() const
{
return DBTREE::url_readcgi( m_url_article, 0, 0 );
}
-const JDLIB::RefPtr_Lock< DBTREE::ArticleBase >& ArticleViewBase::get_article() const noexcept
-{
- assert( m_article );
- return m_article;
-}
-
-
-DrawAreaBase* ArticleViewBase::drawarea()
-{
- assert( m_drawarea );
- return m_drawarea;
-}
-
-
DrawAreaBase* ArticleViewBase::create_drawarea()
{
return Gtk::manage( new ARTICLE::DrawAreaMain( m_url_article ) );
@@ -685,7 +671,7 @@ const char* ArticleViewBase::get_menu_item( const int item )
//
// クライアント領域幅
//
-int ArticleViewBase::width_client()
+int ArticleViewBase::width_client() const
{
#ifdef _DEBUG
if( m_drawarea ) std::cout << "ArticleViewBase::width_client : " << m_drawarea->width_client() << std::endl;
@@ -700,7 +686,7 @@ int ArticleViewBase::width_client()
//
// クライアント領高さ
//
-int ArticleViewBase::height_client()
+int ArticleViewBase::height_client() const
{
#ifdef _DEBUG
if( m_drawarea ) std::cout << "ArticleViewBase::height_client : " << m_drawarea->height_client() << std::endl;
@@ -713,7 +699,7 @@ int ArticleViewBase::height_client()
// アイコンのID取得
-int ArticleViewBase::get_icon( const std::string& iconname )
+int ArticleViewBase::get_icon( const std::string& iconname ) const
{
int id = ICON::NONE;
@@ -1584,7 +1570,7 @@ void ArticleViewBase::slot_setup_abone()
void ArticleViewBase::slot_setup_abone_board()
{
- SKELETON::PrefDiag* pref = CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( m_url_article ), "show_abone_article" );
+ SKELETON::PrefDiag* pref = CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_BOARD, DBTREE::url_boardbase( m_url_article ), "show_abone_article" );
pref->run();
delete pref;
}
@@ -1643,11 +1629,10 @@ void ArticleViewBase::show_res( const std::string& num, const bool show_title )
if( show_title ){
std::string html;
- std::string tmpstr = DBTREE::board_name( m_url_article );
- if( ! tmpstr.empty() ) html += "[ " + tmpstr + " ] ";
+ const std::string& tmpstr = DBTREE::board_name( m_url_article );
+ if( ! tmpstr.empty() ) html += "[ " + MISC::html_escape( tmpstr ) + " ] ";
- tmpstr = DBTREE::article_subject( m_url_article );
- if( ! tmpstr.empty() ) html += tmpstr;
+ html += DBTREE::article_modified_subject( m_url_article );
if( ! html.empty() ) append_html( html );
}
@@ -1715,8 +1700,9 @@ void ArticleViewBase::show_id( const std::string& id_name, const bool show_optio
comment << raw_id << " " << list_resnum.size() << " 件<br>";
comment << "総参照数:" << m_article->get_res_reference( list_resnum ).size() << " 件";
+#if 0
// 末尾判定
- if( raw_id.length() == 9 ){
+ if( raw_id.length() == 12 ){
char c = raw_id.c_str()[ 8 ];
switch( c ){
@@ -1730,6 +1716,7 @@ void ArticleViewBase::show_id( const std::string& id_name, const bool show_optio
case '0': comment << "<br>末尾:" << c << " PC"; break;
}
}
+#endif
if( show_option && ! list_resnum.empty() ){
if( !m_show_url4report ) comment << "<br><br><a href=\"" << PROTO_URL4REPORT << "\">抽出したレスのURLをリスト表示</a>";
@@ -2325,12 +2312,12 @@ void ArticleViewBase::slot_on_url( std::string url, std::string imgurl, int res_
std::string num_str;
const std::string url_dat = DBTREE::url_dat( url, num_from, num_to, num_str );
- const std::string url_subject = DBTREE::url_subject( url );
+ const std::string boardbase = DBTREE::url_boardbase( url );
#ifdef _DEBUG
std::cout << "ArticleViewBase::slot_on_url " << url << std::endl;
std::cout << "url_dat = " << url_dat << std::endl;
- std::cout << "url_subject = " << url_subject << std::endl;
+ std::cout << "boardbase = " << boardbase << std::endl;
std::cout << "num_from = " << num_from << std::endl;
std::cout << "num_to = " << num_to << std::endl;
std::cout << "num = " << num_str << std::endl;
@@ -2348,11 +2335,9 @@ void ArticleViewBase::slot_on_url( std::string url, std::string imgurl, int res_
}
// 板
- else if( ! url_subject.empty() ){
-
- std::string tmpstr = DBTREE::board_name( url );
- args.arg1 = "[ " + tmpstr + " ] ";
+ else if( ! boardbase.empty() ){
+ args.arg1 = "[ " + DBTREE::board_name( url ) + " ] ";
view_popup = CORE::ViewFactory( CORE::VIEW_ARTICLEPOPUPHTML, m_url_article, args );
}
}
@@ -2369,27 +2354,19 @@ void ArticleViewBase::slot_on_url( std::string url, std::string imgurl, int res_
{
std::string tmp = MISC::url_decode( url );
- const int char_code = MISC::judge_char_code( tmp );
+ const CharCode charcode = MISC::judge_char_code( tmp );
- switch( char_code )
+ switch( charcode )
{
- case MISC::CHARCODE_EUC_JP:
+ case CHARCODE_SJIS:
+ case CHARCODE_EUCJP:
+ case CHARCODE_JIS:
- status_url = MISC::Iconv( tmp, "EUC-JP", "UTF-8" );
+ status_url = MISC::Iconv( tmp, charcode, CHARCODE_UTF8 );
break;
- case MISC::CHARCODE_JIS:
-
- status_url = MISC::Iconv( tmp, "ISO-2022-JP", "UTF-8" );
- break;
-
- case MISC::CHARCODE_SJIS:
-
- status_url = MISC::Iconv( tmp, "MS932", "UTF-8" );
- break;
-
- case MISC::CHARCODE_ASCII:
- case MISC::CHARCODE_UTF:
+ case CHARCODE_ASCII:
+ case CHARCODE_UTF8:
status_url = tmp;
break;
@@ -2572,17 +2549,13 @@ bool ArticleViewBase::click_url( std::string url, int res_number, GdkEventButton
hide_popup();
- std::stringstream ssurl;
- ssurl << "http://be.2ch.net/test/p.php?i="
- << url.substr( strlen( PROTO_BE ) )
- << "&u=d:"
- << DBTREE::url_readcgi( m_url_article, res_number, 0 );
+ std::string openurl = "http://be.5ch.net/user/" + url.substr( strlen( PROTO_BE ) );
#ifdef _DEBUG
- std::cout << "open " << ssurl.str() << std::endl;
+ std::cout << "open " << openurl << std::endl;
#endif
- if( control.button_alloted( event, CONTROL::OpenBeButton ) ) CORE::core_set_command( "open_url_browser", ssurl.str() );
+ if( control.button_alloted( event, CONTROL::OpenBeButton ) ) CORE::core_set_command( "open_url_browser", openurl );
else if( control.button_alloted( event, CONTROL::PopupmenuBeButton ) ){
- show_popupmenu( ssurl.str(), false );
+ show_popupmenu( openurl, false );
}
}
@@ -3425,7 +3398,7 @@ void ArticleViewBase::slot_search_cachelocal()
if( query.empty() ) return;
- const std::string url = DBTREE::url_subject( m_url_article );
+ const std::string url = DBTREE::url_boardbase( m_url_article );
#ifdef _DEBUG
std::cout << "ArticleViewBase::slot_search_cachelocal " << url << std::endl
@@ -3443,7 +3416,7 @@ void ArticleViewBase::slot_search_next()
{
if( m_article->empty() ) return;
- CORE::core_set_command( "open_board_next", DBTREE::url_subject( m_url_article ) , m_url_article );
+ CORE::core_set_command( "open_board_next", DBTREE::url_boardbase( m_url_article ) , m_url_article );
}
@@ -3684,9 +3657,9 @@ void ArticleViewBase::slot_copy_res( bool ref )
std::string tmpstr = m_url_tmp + "\n";
if( ref ) tmpstr += CONFIG::get_ref_prefix();
- std::string board_name = DBTREE::board_name( m_url_article );
+ const std::string& board_name = DBTREE::board_name( m_url_article );
if( ! board_name.empty() ) tmpstr += "[ " + board_name + " ] ";
- tmpstr += DBTREE::article_subject( m_url_article ) + "\n\n";
+ tmpstr += MISC::to_plain( DBTREE::article_subject( m_url_article ) ) + "\n\n";
tmpstr += m_article->get_res_str( atoi( m_str_num.c_str() ), ref );
MISC::CopyClipboard( tmpstr );
@@ -3698,7 +3671,7 @@ void ArticleViewBase::slot_copy_res( bool ref )
//
void ArticleViewBase::slot_copy_title_url()
{
- MISC::CopyClipboard( DBTREE::article_subject( m_url_article ) + '\n' + url_for_copy() );
+ MISC::CopyClipboard( MISC::to_plain( DBTREE::article_subject( m_url_article ) ) + '\n' + url_for_copy() );
}
@@ -3713,7 +3686,7 @@ void ArticleViewBase::set_favorite()
info.type = TYPE_THREAD;
info.parent = ARTICLE::get_admin()->get_win();
info.url = m_url_article;;
- info.name = DBTREE::article_subject( m_url_article );
+ info.name = MISC::to_plain( DBTREE::article_modified_subject( m_url_article ) );
info.path = Gtk::TreePath( "0" ).to_string();
CORE::DATA_INFO_LIST list_info;
diff --git a/src/article/articleviewbase.h b/src/article/articleviewbase.h
index fe679a89..f6b321e0 100644
--- a/src/article/articleviewbase.h
+++ b/src/article/articleviewbase.h
@@ -102,10 +102,10 @@ namespace ARTICLE
void save_session() override {}
- std::string url_for_copy() override; // コピーやURLバー表示用のURL
- int width_client() override;
- int height_client() override;
- int get_icon( const std::string& iconname ) override;
+ std::string url_for_copy() const override; // コピーやURLバー表示用のURL
+ int width_client() const override;
+ int height_client() const override;
+ int get_icon( const std::string& iconname ) const override;
bool set_command( const std::string& command,
const std::string& arg1 = {},
const std::string& arg2 = {} ) override;
@@ -151,14 +151,15 @@ namespace ARTICLE
// 実況モードか
bool get_live() const { return m_live; }
- DrawAreaBase* drawarea();
+ DrawAreaBase* drawarea() const noexcept { return m_drawarea; }
protected:
// Viewが所属するAdminクラス
SKELETON::Admin* get_admin() override;
- const JDLIB::RefPtr_Lock< DBTREE::ArticleBase >& get_article() const noexcept;
+ JDLIB::RefPtr_Lock< DBTREE::ArticleBase >& get_article() noexcept { return m_article; };
+ const JDLIB::RefPtr_Lock< DBTREE::ArticleBase >& get_article() const noexcept { return m_article; };
// ポップアップメニューを表示する前にメニューのアクティブ状態を切り替える
void activate_act_before_popupmenu( const std::string& url ) override;
diff --git a/src/article/articleviewetc.cpp b/src/article/articleviewetc.cpp
index 37fbf72a..9a9f35fd 100644
--- a/src/article/articleviewetc.cpp
+++ b/src/article/articleviewetc.cpp
@@ -11,6 +11,7 @@
#include "dbtree/articlebase.h"
#include "control/controlid.h"
+#include "jdlib/miscutil.h"
#include "global.h"
@@ -37,7 +38,7 @@ ArticleViewRes::ArticleViewRes( const std::string& url )
setup_view();
// ラベル更新
- set_label( " [ RES:" + m_str_num + " ] - " + DBTREE::article_subject( url_article() ) );
+ set_label( " [ RES:" + m_str_num + " ] - " + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -57,7 +58,7 @@ ArticleViewRes::~ArticleViewRes()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewRes::relayout()
+void ArticleViewRes::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewRes::relayout\n";
@@ -118,7 +119,7 @@ ArticleViewName::ArticleViewName( const std::string& url )
setup_view();
// ラベル更新
- set_label( " [ 名前:" + m_str_name + " ] - " + DBTREE::article_subject( url_article() ));
+ set_label( " [ 名前:" + m_str_name + " ] - " + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -138,7 +139,7 @@ ArticleViewName::~ArticleViewName()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewName::relayout()
+void ArticleViewName::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewName::relayout\n";
@@ -196,7 +197,7 @@ ArticleViewID::ArticleViewID( const std::string& url )
setup_view();
// ラベル更新
- set_label( " [ " + m_str_id.substr( strlen( PROTO_ID ) ) + " ] - " + DBTREE::article_subject( url_article() ));
+ set_label( " [ " + m_str_id.substr( strlen( PROTO_ID ) ) + " ] - " + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -216,7 +217,7 @@ ArticleViewID::~ArticleViewID()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewID::relayout()
+void ArticleViewID::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewID::relayout\n";
@@ -272,7 +273,7 @@ ArticleViewBM::ArticleViewBM( const std::string& url )
setup_view();
// ラベル更新
- set_label( " [ しおり ] - " + DBTREE::article_subject( url_article() ));
+ set_label( " [ しおり ] - " + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -292,7 +293,7 @@ ArticleViewBM::~ArticleViewBM()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewBM::relayout()
+void ArticleViewBM::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewBM::relayout\n";
@@ -349,7 +350,7 @@ ArticleViewPost::ArticleViewPost( const std::string& url )
// ラベル更新
- set_label( " [ 書き込み ] - " + DBTREE::article_subject( url_article() ));
+ set_label( " [ 書き込み ] - " + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -369,7 +370,7 @@ ArticleViewPost::~ArticleViewPost()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewPost::relayout()
+void ArticleViewPost::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewPost::relayout\n";
@@ -424,7 +425,7 @@ ArticleViewURL::ArticleViewURL( const std::string& url )
setup_view();
// ラベル更新
- set_label( " [ URL ] - " + DBTREE::article_subject( url_article() ));
+ set_label( " [ URL ] - " + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -444,7 +445,7 @@ ArticleViewURL::~ArticleViewURL()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewURL::relayout()
+void ArticleViewURL::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewURL::relayout\n";
@@ -503,7 +504,7 @@ ArticleViewRefer::ArticleViewRefer( const std::string& url )
setup_view();
// ラベル更新
- set_label( " [ Re:" + m_str_num + " ] - " + DBTREE::article_subject( url_article() ));
+ set_label( " [ Re:" + m_str_num + " ] - " + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -523,7 +524,7 @@ ArticleViewRefer::~ArticleViewRefer()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewRefer::relayout()
+void ArticleViewRefer::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewRefer::relayout\n";
@@ -590,7 +591,7 @@ ArticleViewDrawout::ArticleViewDrawout( const std::string& url )
std::string str_label;
if( m_mode_or ) str_label = "[ OR 抽出 ] - ";
else str_label = "[ AND 抽出 ] - ";
- set_label( str_label + DBTREE::article_subject( url_article() ) );
+ set_label( str_label + MISC::to_markup( DBTREE::article_modified_subject( url_article() ) ), true );
// タブ更新
ARTICLE::get_admin()->set_command( "set_tablabel", get_url(), get_label() );
@@ -611,7 +612,7 @@ ArticleViewDrawout::~ArticleViewDrawout()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewDrawout::relayout()
+void ArticleViewDrawout::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewDrawout::relayout\n";
@@ -706,7 +707,7 @@ void ArticleViewPostlog::operate_search( const std::string& controlid )
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewPostlog::relayout()
+void ArticleViewPostlog::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewPostlog::relayout\n";
diff --git a/src/article/articleviewetc.h b/src/article/articleviewetc.h
index 38f05d1d..45c00c65 100644
--- a/src/article/articleviewetc.h
+++ b/src/article/articleviewetc.h
@@ -22,7 +22,7 @@ namespace ARTICLE
~ArticleViewRes();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -46,7 +46,7 @@ namespace ARTICLE
~ArticleViewName();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -70,7 +70,7 @@ namespace ARTICLE
~ArticleViewID();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -94,7 +94,7 @@ namespace ARTICLE
~ArticleViewBM();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -119,7 +119,7 @@ namespace ARTICLE
~ArticleViewPost();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -142,7 +142,7 @@ namespace ARTICLE
~ArticleViewURL();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -166,7 +166,7 @@ namespace ARTICLE
~ArticleViewRefer();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -192,7 +192,7 @@ namespace ARTICLE
~ArticleViewDrawout();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void show_view() override;
void reload() override;
@@ -215,7 +215,7 @@ namespace ARTICLE
~ArticleViewPostlog();
// SKELETON::View の関数のオーバロード
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void stop() override {} // キャンセル
// 検索
diff --git a/src/article/articleviewpopup.h b/src/article/articleviewpopup.h
index 52ff0c1e..5ab4cda7 100644
--- a/src/article/articleviewpopup.h
+++ b/src/article/articleviewpopup.h
@@ -41,7 +41,7 @@ namespace ARTICLE
public:
ArticleViewPopupHTML( const std::string& url, const std::string& html ): ArticleViewPopup( url, false ), m_html( html ){}
- ~ArticleViewPopupHTML() noexcept {}
+ ~ArticleViewPopupHTML() noexcept = default;
void show_view() override { append_html( m_html ); }
};
@@ -59,7 +59,7 @@ namespace ARTICLE
public:
ArticleViewPopupRes( const std::string& url, const std::string& num, bool show_title, bool show_abone )
: ArticleViewPopup( url, show_abone ), m_str_num( num ), m_show_title( show_title ){}
- ~ArticleViewPopupRes() noexcept {}
+ ~ArticleViewPopupRes() noexcept = default;
void show_view() override
{
@@ -79,7 +79,7 @@ namespace ARTICLE
public:
ArticleViewPopupName( const std::string& url, const std::string& name ): ArticleViewPopup( url, false ), m_str_name( name ){}
- ~ArticleViewPopupName() noexcept {}
+ ~ArticleViewPopupName() noexcept = default;
void show_view() override
{
@@ -99,7 +99,7 @@ namespace ARTICLE
public:
ArticleViewPopupID( const std::string& url, const std::string& id ): ArticleViewPopup( url, false ), m_str_id( id ) {}
- ~ArticleViewPopupID() noexcept {}
+ ~ArticleViewPopupID() noexcept = default;
void show_view() override
{
@@ -119,7 +119,7 @@ namespace ARTICLE
public:
ArticleViewPopupRefer( const std::string& url, const std::string& num ): ArticleViewPopup( url, false ), m_str_num( num ){}
- ~ArticleViewPopupRefer() noexcept {}
+ ~ArticleViewPopupRefer() noexcept = default;
void show_view() override
{
@@ -139,7 +139,7 @@ namespace ARTICLE
public:
ArticleViewPopupDrawout( const std::string& url, const std::string& query, bool mode_or )
: ArticleViewPopup( url, false ), m_query( query ), m_mode_or( mode_or ){}
- ~ArticleViewPopupDrawout() noexcept {}
+ ~ArticleViewPopupDrawout() noexcept = default;
void show_view() override
{
@@ -156,7 +156,7 @@ namespace ARTICLE
{
public:
ArticleViewPopupBM( const std::string& url ) : ArticleViewPopup( url, false ){}
- ~ArticleViewPopupBM() noexcept {}
+ ~ArticleViewPopupBM() noexcept = default;
void show_view() override
{
diff --git a/src/article/articleviewsearch.cpp b/src/article/articleviewsearch.cpp
index a38908a8..cd60e90c 100644
--- a/src/article/articleviewsearch.cpp
+++ b/src/article/articleviewsearch.cpp
@@ -186,7 +186,7 @@ void ArticleViewSearch::regex_escape()
//
// メインウィンドウのURLバーなどの表示用にも使う
//
-std::string ArticleViewSearch::url_for_copy()
+std::string ArticleViewSearch::url_for_copy() const
{
if( m_searchmode == CORE::SEARCHMODE_TITLE ) return m_url_title;
@@ -245,7 +245,7 @@ void ArticleViewSearch::show_view()
//
// 画面を消してレイアウトやりなおし & 再描画
//
-void ArticleViewSearch::relayout()
+void ArticleViewSearch::relayout( const bool completely )
{
#ifdef _DEBUG
std::cout << "ArticleViewSearch::relayout\n";
@@ -260,7 +260,7 @@ void ArticleViewSearch::relayout()
if( m_searchmode == CORE::SEARCHMODE_ALLLOG ) comment << "検索対象:キャッシュ内の全ログ<br>";
else if( m_searchmode == CORE::SEARCHMODE_TITLE ) comment << "検索サイト : "
+ MISC::get_hostname( CONFIG::get_url_search_title() ) + "<br>";
- else comment << "検索対象:" << DBTREE::board_name( m_url_board ) << "<br>";
+ else comment << "検索対象:" << MISC::html_escape( DBTREE::board_name( m_url_board ) ) << "<br>";
if( get_bm() ) comment << "検索条件:しおり<br>";
@@ -288,9 +288,9 @@ void ArticleViewSearch::relayout()
// 板名表示
if( m_searchmode == CORE::SEARCHMODE_ALLLOG || m_searchmode == CORE::SEARCHMODE_TITLE )
- comment << "[ <a href=\"" << DBTREE::url_subject( (*it).url_readcgi ) << "\">" << (*it).boardname << "</a> ] ";
+ comment << "[ <a href=\"" << DBTREE::url_boardbase( (*it).url_readcgi ) << "\">" << MISC::html_escape( (*it).boardname ) << "</a> ] ";
- comment << "<a href=\"" << (*it).url_readcgi << "\">" << MISC::html_escape( (*it).subject ) << "</a>";
+ comment << "<a href=\"" << (*it).url_readcgi << "\">" << (*it).subject << "</a>";
if( (*it).num ) comment << " ( " << (*it).num << " )";
diff --git a/src/article/articleviewsearch.h b/src/article/articleviewsearch.h
index 4b869f68..0b5604e7 100644
--- a/src/article/articleviewsearch.h
+++ b/src/article/articleviewsearch.h
@@ -35,7 +35,7 @@ namespace ARTICLE
// SKELETON::View の関数のオーバロード
- std::string url_for_copy() override; // コピーやURLバー表示用のURL
+ std::string url_for_copy() const override; // コピーやURLバー表示用のURL
bool set_command( const std::string& command,
const std::string& arg1 = {},
const std::string& arg2 = {} ) override;
@@ -44,7 +44,7 @@ namespace ARTICLE
void focus_view() override;
void show_view() override;
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void reload() override;
void stop() override;
diff --git a/src/article/drawareabase.cpp b/src/article/drawareabase.cpp
index 104d93f8..e7e63c3c 100644
--- a/src/article/drawareabase.cpp
+++ b/src/article/drawareabase.cpp
@@ -11,6 +11,7 @@
#include "font.h"
#include "embeddedimage.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/miscmsg.h"
#include "jdlib/jdregex.h"
@@ -585,13 +586,15 @@ int DrawAreaBase::get_current_res_num()
// 先頭のヘッダブロックから順に調べる
LAYOUT* header = m_layout_tree->top_header();
- while( header ){
+ LAYOUT* next_header = header ? header->next_header : NULL;
+ while( next_header ){
// y が含まれているブロックを探す
- if( header->rect->y >= y ) return header->res_number -1;
+ if( next_header->rect->y >= y ) return header->res_number;
// 次のブロックへ
- header = header->next_header;
+ header = next_header;
+ next_header = header->next_header;
}
return max_number();
@@ -942,7 +945,8 @@ bool DrawAreaBase::exec_layout_impl( const bool is_popup, const int offset_y )
// フォント設定
set_node_font( header );
- CORE::get_css_manager()->set_size( &m_css_body, m_font->height );
+ const CORE::Css_Manager *cssmgr = CORE::get_css_manager();
+ cssmgr->set_size( &m_css_body, m_font->height );
y += offset_y * m_font->br_size;
y += m_css_body.padding_top;
@@ -957,7 +961,7 @@ bool DrawAreaBase::exec_layout_impl( const bool is_popup, const int offset_y )
// (注) header は div ノードであり、クラス名は "res"
// 詳しくは LayoutTree::create_layout_header() を参照せよ
- CORE::get_css_manager()->set_size( header->css, m_font->height );
+ cssmgr->set_size( header->css, m_font->height );
// div の位置と幅を計算
// 高さは子ノードのレイアウトが全て済んでから計算
@@ -1007,7 +1011,7 @@ bool DrawAreaBase::exec_layout_impl( const bool is_popup, const int offset_y )
// div の位置と幅を計算
// 高さは違う div に切り替わった時に計算
- CORE::get_css_manager()->set_size( current_div->css, m_font->height );
+ cssmgr->set_size( current_div->css, m_font->height );
x = header->rect->x + header->css->padding_left;
x += current_div->css->mrg_left;
y += current_div->css->mrg_top;
@@ -1519,13 +1523,20 @@ void DrawAreaBase::layout_one_text_node( LAYOUT* layout, int& x, int& y, int& br
if( pos_to >= byte_to ) break;
// wrap 処理
- x = 0;
- if( div ) x = div->rect->x + div->css->padding_left;
+ x = div ? div->rect->x + div->css->padding_left : 0;
y += br_size;
br_size = m_font->br_size; // 次の行の改行位置をリセット
pos_start = pos_to;
}
+
+ // 次のノードが改行でなければ wrap するか確認する
+ if( layout->next_layout && layout->next_layout->type != DBTREE::NODE_BR
+ && is_wrapped( x, border, " " ) ){
+ x = div ? div->rect->x + div->css->padding_left : 0;
+ y += br_size;
+ br_size = m_font->br_size; // 次の行の改行位置をリセット
+ }
}
@@ -1608,8 +1619,7 @@ bool DrawAreaBase::set_init_wide_mode( const char* str, const int pos_start, con
int i = pos_start;
while( i < pos_to ){
- int byte_tmp;
- MISC::utf8toucs2( str + i, byte_tmp );
+ const int byte_tmp = MISC::utf8bytes( str + i );
// 文字列に全角が含まれていたら全角モードで開始
if( byte_tmp != 1 ) break;
@@ -1643,8 +1653,22 @@ int DrawAreaBase::get_width_of_one_char( const char* utfstr, int& byte, char& pr
int width = 0;
int width_wide = 0;
+ const int code = MISC::utf8tocp( utfstr, byte );
+
+ if( ! byte ){
+#ifdef _DEBUG
+ std::cout << "DrawAreaBase::get_width_of_one_char "
+ << "invalid char " << (unsigned char)utfstr[ 0 ]
+ << " " << (unsigned char)utfstr[ 1 ]
+ << " " << (unsigned char)utfstr[ 2 ]
+ << " " << (unsigned char)utfstr[ 3 ] << std::endl;
+#endif
+ byte = 1;
+ return 0;
+ }
+
// キャッシュに無かったら幅を調べてキャッシュに登録
- if( ! ARTICLE::get_width_of_char( utfstr, byte, pre_char, width, width_wide, mode ) ){
+ if( ! ARTICLE::get_width_of_char( code, pre_char, width, width_wide, mode ) ){
const std::string tmpchar( utfstr, byte );
@@ -1706,26 +1730,26 @@ int DrawAreaBase::get_width_of_one_char( const char* utfstr, int& byte, char& pr
// フォントが無い
if( width_wide <= 0 ){
- int byte_tmp;
- const unsigned int code = MISC::utf8toucs2( tmpchar.c_str(), byte_tmp );
-
- std::stringstream ss_err;
- ss_err << "unknown font byte = " << byte_tmp << " ucs2 = " << code << " width = " << width;
-
#ifdef _DEBUG
std::cout << "DrawAreaBase::get_width_of_one_char "
<< "byte = " << byte
- << " byte_tmp = " << byte_tmp
<< " code = " << code
<< " [" << tmpchar << "]\n";
#endif
- MISC::ERRMSG( ss_err.str() );
+ if( ( code < 0xE000 || code > 0xF8FF ) // 基本面私用領域ではない
+ && ( code < 0xF0000 || code > 0x10FFFF ) // 私用面ではない
+ ){
+ std::stringstream ss_err;
+ ss_err << "unknown font byte = " << byte << " ucs = " << code << " width = " << width;
- ARTICLE::set_width_of_char( utfstr, byte, pre_char, -1, -1, mode );
+ MISC::ERRMSG( ss_err.str() );
+ }
+
+ ARTICLE::set_width_of_char( code, pre_char, -1, -1, mode );
width = width_wide = 0;
}
- else ARTICLE::set_width_of_char( utfstr, byte, pre_char, width, width_wide, mode );
+ else ARTICLE::set_width_of_char( code, pre_char, width, width_wide, mode );
}
int ret = 0;
@@ -2387,7 +2411,9 @@ bool DrawAreaBase::draw_one_node( LAYOUT* layout, const CLIPINFO& ci )
if( layout->rect ){
const int x = layout->rect->x;
const int y = layout->rect->y - ci.pos_y;
- const int color_text = get_colorid_text();
+ int color_text = get_colorid_text();
+ if( color_text == COLOR_CHAR && layout->div && layout->div->css->color >= 0 )
+ color_text = layout->div->css->color;
#if GTKMM_CHECK_VERSION(3,0,0)
cairo_t* const cr = cairo_create( m_backscreen.get() );
gdk_cairo_set_source_rgba( cr, m_color[ color_text ].gobj() );
@@ -2797,7 +2823,8 @@ void DrawAreaBase::draw_one_text_node( LAYOUT* layout, const CLIPINFO& ci )
if( color_text == COLOR_CHAR && layout->div && layout->div->css->color >= 0 ) color_text = layout->div->css->color;
int color_back = get_colorid_back();
- if( layout->div && layout->div->css->bg_color >= 0 ) color_back = layout->div->css->bg_color;
+ if( layout->node && layout->node->color_back != COLOR_NONE ) color_back = layout->node->color_back;
+ else if( layout->div && layout->div->css->bg_color >= 0 ) color_back = layout->div->css->bg_color;
else if( layout->header && layout->header->css->bg_color >= 0 ) color_back = layout->header->css->bg_color;
// 通常描画
@@ -2911,7 +2938,7 @@ bool DrawAreaBase::draw_one_img_node( LAYOUT* layout, const CLIPINFO& ci )
// 描画
else{
- Glib::RefPtr< Gdk::Pixbuf > pixbuf = layout->eimg->get_pixbuf();
+ Glib::RefPtr< Gdk::Pixbuf >& pixbuf = layout->eimg->get_pixbuf();
if( pixbuf ){
const int s_top = MAX( 0, ci.upper - ( rect->y + 1 ) );
@@ -3053,6 +3080,8 @@ void DrawAreaBase::draw_string( LAYOUT* node, const CLIPINFO& ci,
}
}
+ if( color >= int( m_color.size() ) || color_back >= int( m_color.size() ) ) init_color();
+
if( width_line ){
const int xx = x;
@@ -3087,7 +3116,12 @@ void DrawAreaBase::draw_string( LAYOUT* node, const CLIPINFO& ci,
pango_cairo_show_layout( text_cr, m_pango_layout->gobj() );
}
#else
- m_pango_layout->set_text( Glib::ustring( node->text + pos_start, n_ustr ) );
+ // Glib::ustringのコンストラクタでchar*から変換するとUTF-8が
+ // 壊れている場合にインスタンスが生成されない
+ // (例外をキャッチしないとクラッシュする)ので
+ // std::stringからGlib::ustringに変換するコンストラクタを使う
+ //m_pango_layout->set_text( Glib::ustring( node->text + pos_start, n_ustr ) );
+ m_pango_layout->set_text( std::string( node->text + pos_start, n_byte ) );
m_backscreen->draw_layout( m_gc,x, y, m_pango_layout, m_color[ color ], m_color[ color_back ] );
if( node->bold ){
@@ -3793,11 +3827,13 @@ int DrawAreaBase::search( const std::list< std::string >& list_query, const bool
if( list_query.size() == 0 ) return 0;
- std::list< JDLIB::Regex > list_regex;
+ JDLIB::Regex regex;
+ std::list< JDLIB::RegexPattern > list_regex;
const bool icase = true; // 大文字小文字区別しない
const bool newline = true; // . に改行をマッチさせない
const bool usemigemo = true; // migemo使用
- const bool wchar = true; // 全角半角の区別をしない
+ const bool wchar = false; // 全角半角の区別をしない
+ const bool norm = true; // Unicodeの互換文字を区別しない
#ifdef _DEBUG
std::cout << "ArticleViewBase::search size = " << list_query.size() << std::endl;
@@ -3806,10 +3842,8 @@ int DrawAreaBase::search( const std::list< std::string >& list_query, const bool
std::list< std::string >::const_iterator it_query;
for( it_query = list_query.begin(); it_query != list_query.end() ; ++it_query ){
- const std::string &query = ( *it_query );
-
- list_regex.push_back( JDLIB::Regex() );
- list_regex.back().compile( query, icase, newline, usemigemo, wchar );
+ list_regex.push_back( JDLIB::RegexPattern() );
+ list_regex.back().set( *it_query, icase, newline, usemigemo, wchar, norm );
}
m_multi_selection.clear();
@@ -3846,7 +3880,7 @@ int DrawAreaBase::search( const std::list< std::string >& list_query, const bool
const size_t lng = strlen( tmplayout->text );
- if( buffer_lng + lng > SEARCH_BUFFER_SIZE ){
+ if( buffer_lng + lng >= SEARCH_BUFFER_SIZE ){
MISC::ERRMSG( "DrawAreaBase::search : buffer overflow." );
break;
@@ -3872,11 +3906,10 @@ int DrawAreaBase::search( const std::list< std::string >& list_query, const bool
int min_offset = -1;
int lng = 0;
- std::list< JDLIB::Regex >::iterator it_regex;
+ std::list< JDLIB::RegexPattern >::iterator it_regex;
for( it_regex = list_regex.begin(); it_regex != list_regex.end() ; ++it_regex ){
- JDLIB::Regex &regex = ( *it_regex );
- if( regex.exec( target, offset ) ){
+ if( regex.match( *it_regex, target, offset ) ){
if( min_offset == -1 || regex.pos( 0 ) <= min_offset ){
min_offset = regex.pos( 0 );
@@ -4453,15 +4486,15 @@ bool DrawAreaBase::set_carets_dclick( CARET_POSITION& caret_left, CARET_POSITION
}
int byte_char_pointer;
- const int ucs2_pointer = MISC::utf8toucs2( layout->text + pos, byte_char_pointer );
- const int ucs2mode_pointer = MISC::get_ucs2mode( ucs2_pointer );
+ const int ucs_pointer = MISC::utf8tocp( layout->text + pos, byte_char_pointer );
+ const int ucstype_pointer = MISC::get_ucstype( ucs_pointer );
#ifdef _DEBUG
- std::cout << "ucs2 = " << std::hex << ucs2_pointer << std::dec
- << " mode = " << ucs2mode_pointer << " pos = " << pos << std::endl;
+ std::cout << "ucs = " << std::hex << ucs_pointer << std::dec
+ << " type = " << ucstype_pointer << " pos = " << pos << std::endl;
#endif
// 区切り文字をダブルクリックした
- if( is_separate_char( ucs2_pointer ) ){
+ if( is_separate_char( ucs_pointer ) ){
caret_left.set( layout, pos );
caret_right.set( layout, pos + byte_char_pointer );
return true;
@@ -4473,24 +4506,21 @@ bool DrawAreaBase::set_carets_dclick( CARET_POSITION& caret_left, CARET_POSITION
while( pos_tmp < pos ){
int byte_char;
- const int ucs2 = MISC::utf8toucs2( layout->text + pos_tmp, byte_char );
- const int ucs2mode = MISC::get_ucs2mode( ucs2 );
+ const int ucs = MISC::utf8tocp( layout->text + pos_tmp, byte_char );
+ const int ucstype = MISC::get_ucstype( ucs );
int byte_char_next;
- const int ucs2_next = MISC::utf8toucs2( layout->text + pos_tmp + byte_char, byte_char_next );
- const int ucs2mode_next = MISC::get_ucs2mode( ucs2_next );
+ const int ucs_next = MISC::utf8tocp( layout->text + pos_tmp + byte_char, byte_char_next );
+ const int ucstype_next = MISC::get_ucstype( ucs_next );
// 区切り文字が来たら左位置を移動する
- if( ucs2_next == '\0'
-
- || is_separate_char( ucs2 )
-
+ if( ucs_next == '\0' || is_separate_char( ucs )
// 文字種が変わった
- || ( ucs2mode != ucs2mode_pointer && ucs2mode_next == ucs2mode_pointer )
+ || ( ucstype != ucstype_pointer && ucstype_next == ucstype_pointer )
) pos_left = pos_tmp + byte_char;
- pos_tmp += byte_char;
+ pos_tmp += ( byte_char ? byte_char : 1 );
}
// 右位置を求める
@@ -4498,21 +4528,21 @@ bool DrawAreaBase::set_carets_dclick( CARET_POSITION& caret_left, CARET_POSITION
while( pos_right < layout->lng_text ){
int byte_char;
- const int ucs2 = MISC::utf8toucs2( layout->text + pos_right, byte_char );
- const int ucs2mode = MISC::get_ucs2mode( ucs2 );
+ const int ucs = MISC::utf8tocp( layout->text + pos_right, byte_char );
+ const int ucstype = MISC::get_ucstype( ucs );
int byte_char_next;
- const int ucs2_next = MISC::utf8toucs2( layout->text + pos_right + byte_char, byte_char_next );
- const int ucs2mode_next = MISC::get_ucs2mode( ucs2_next );
+ const int ucs_next = MISC::utf8tocp( layout->text + pos_right + byte_char, byte_char_next );
+ const int ucstype_next = MISC::get_ucstype( ucs_next );
// 区切り文字が来たらbreak
- if( is_separate_char( ucs2 ) ) break;
+ if( is_separate_char( ucs ) ) break;
- pos_right += byte_char;
+ pos_right += ( byte_char ? byte_char : 1 );
// 文字種が変わった
- if( ucs2_next == '\0'
- || ( ucs2mode == ucs2mode_pointer && ucs2mode_next != ucs2mode_pointer )
+ if( ucs_next == '\0'
+ || ( ucstype == ucstype_pointer && ucstype_next != ucstype_pointer )
) break;
}
diff --git a/src/article/embeddedimage.cpp b/src/article/embeddedimage.cpp
index 31825b10..9206dc1e 100644
--- a/src/article/embeddedimage.cpp
+++ b/src/article/embeddedimage.cpp
@@ -84,8 +84,6 @@ void EmbeddedImage::stop()
#ifdef _DEBUG
std::cout << "EmbeddedImage::stop" << std::endl;
#endif
- if( m_imgloader )
- m_imgloader->request_stop();
}
@@ -137,8 +135,8 @@ void EmbeddedImage::resize_thread()
if( m_img->get_type() == DBIMG::T_BMP ) pixbufonly = false; // BMP の場合 pixbufonly = true にすると真っ黒になる
- m_imgloader = JDLIB::ImgLoader::get_loader( m_img->get_cache_path() );
- Glib::RefPtr<Gdk::Pixbuf> pixbuf = m_imgloader->get_pixbuf( pixbufonly );
+ Glib::RefPtr<JDLIB::ImgLoader> imgloader = JDLIB::ImgLoader::get_loader( m_img->get_cache_path() );
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = imgloader->get_pixbuf( pixbufonly );
if( pixbuf ){
Gdk::InterpType interptype = Gdk::INTERP_NEAREST;
if( CONFIG::get_imgemb_interp() == 1 ) interptype = Gdk::INTERP_BILINEAR;
@@ -146,7 +144,7 @@ void EmbeddedImage::resize_thread()
m_pixbuf = pixbuf->scale_simple( width, height, interptype );
}
- m_imgloader.reset();
+ imgloader.reset();
// メインスレッドにリサイズが終わったことを知らせて
// メインスレッドがpthread_join()を呼び出す
diff --git a/src/article/embeddedimage.h b/src/article/embeddedimage.h
index 57fde9a4..3cf44b20 100644
--- a/src/article/embeddedimage.h
+++ b/src/article/embeddedimage.h
@@ -28,14 +28,12 @@ namespace ARTICLE
JDLIB::ConstPtr< DBIMG::Img > m_img;
JDLIB::Thread m_thread;
- Glib::RefPtr< JDLIB::ImgLoader > m_imgloader;
-
public:
EmbeddedImage( const std::string& url );
~EmbeddedImage();
- Glib::RefPtr< Gdk::Pixbuf > get_pixbuf(){ return m_pixbuf; }
+ Glib::RefPtr< Gdk::Pixbuf >& get_pixbuf(){ return m_pixbuf; }
void show();
void resize_thread();
diff --git a/src/article/font.cpp b/src/article/font.cpp
index 0e2b30c6..e8227ef0 100644
--- a/src/article/font.cpp
+++ b/src/article/font.cpp
@@ -5,8 +5,6 @@
#include "font.h"
-#include "jdlib/miscutil.h"
-
#include "fontid.h"
#include "config/globalconf.h"
@@ -29,7 +27,7 @@ static bool strict_of_char = false;
enum
{
- UCS2_MAX = 1114111
+ NUM_CHAR_MAX = 0x110000 // フォントの幅を記録する文字数
};
@@ -45,14 +43,13 @@ void ARTICLE::init_font()
if( width_of_char[ i ] ){
- for( int j = 0; j < UCS2_MAX; ++j ){
+ for( int j = 0; j < NUM_CHAR_MAX; ++j ){
if( width_of_char[ i ][ j ].width ) delete[] width_of_char[ i ][ j ].width;
}
delete[] width_of_char[ i ];
+ width_of_char[ i ] = nullptr;
}
-
- width_of_char[ i ] = NULL;
}
}
@@ -61,50 +58,64 @@ void ARTICLE::init_font()
//
// 登録された文字の幅を返す関数
//
-// utfstr : 入力文字 (UTF-8)
-// byte : 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す
+// code : 入力文字 (コードポイント)
// pre_char : ひとつ前の文字 ( 前の文字が全角の場合は 0 )
// width : 半角モードでの幅
// width_wide : 全角モードでの幅
// mode : fontid.h で定義されているフォントのID
// 戻り値 : 登録されていればtrue
//
-bool ARTICLE::get_width_of_char( const char* utfstr, int& byte, const char pre_char, int& width, int& width_wide, const int mode )
+bool ARTICLE::get_width_of_char( const int code, const char pre_char, int& width, int& width_wide, const int mode )
{
- byte = 0;
width = 0;
width_wide = 0;
if( ! width_of_char[ mode ] ){
- width_of_char[ mode ] = new WIDTH_DATA[ UCS2_MAX ]{} ;
+ width_of_char[ mode ] = new WIDTH_DATA[ NUM_CHAR_MAX ]{};
+
+ // 合成文字の初期化
+ for( int i = 0x300; i <= 0x36f; i++ ) // Combining Diacritical Marks
+ width_of_char[ mode ][ i ].width_wide = -1;
+ for( int i = 0x180b; i <= 0x180d; i++ ) // Mongolian Free Variation Selector
+ width_of_char[ mode ][ i ].width_wide = -1;
+ for( int i = 0x200b; i <= 0x200f; i++ ) // ZWSP,ZWNJ,ZWJ,LRM,RLM
+ width_of_char[ mode ][ i ].width_wide = -1;
+ for( int i = 0x202a; i <= 0x202e; i++ ) // LRE,RLE,PDF,LRO,RLO
+ width_of_char[ mode ][ i ].width_wide = -1;
+ for( int i = 0x20d0; i <= 0x20ff; i++ ) // Combining Diacritical Marks for Symbols
+ width_of_char[ mode ][ i ].width_wide = -1;
+ for( int i = 0x3099; i <= 0x309a; i++ ) // COMBINING KATAKANA-HIRAGANA (SEMI-)VOICED SOUND MARK
+ width_of_char[ mode ][ i ].width_wide = -1;
+ for( int i = 0xfe00; i <= 0xfe0f; i++ ) // VS1-VS16
+ width_of_char[ mode ][ i ].width_wide = -1;
+ width_of_char[ mode ][ 0xfeff ].width_wide = -1; // ZERO WIDTH NO-BREAK SPACE
}
- const int ucs2 = MISC::utf8toucs2( utfstr, byte );
- if( byte && ucs2 < UCS2_MAX ){
+ if( code > 0 && code < NUM_CHAR_MAX ){
// 全角モードの幅
- width_wide = width_of_char[ mode ][ ucs2 ].width_wide;
+ width_wide = width_of_char[ mode ][ code ].width_wide;
// 半角モードの幅
width = width_wide;
// 厳密に求める場合
- if( byte == 1 && strict_of_char ){
+ if( code < 128 && strict_of_char ){
- if( ! width_of_char[ mode ][ ucs2 ].width ){
- width_of_char[ mode ][ ucs2 ].width = new unsigned int[ 128 ]{} ;
+ if( ! width_of_char[ mode ][ code ].width ){
+ width_of_char[ mode ][ code ].width = new unsigned int[ 128 ]{};
}
const int pre_char_num = ( int ) pre_char;
- if( pre_char_num < 128 ) width = width_of_char[ mode ][ ucs2 ].width[ pre_char_num ];
+ if( pre_char_num < 128 ) width = width_of_char[ mode ][ code ].width[ pre_char_num ];
}
}
- if( width && width_wide ) return true;
- else if( width == -1 ){ // フォント幅の取得に失敗した場合
+ if( width == -1 ){ // フォント幅の取得に失敗した場合
width = width_wide = 0;
return true;
}
+ else if( width && width_wide ) return true;
return false;
}
@@ -116,19 +127,17 @@ bool ARTICLE::get_width_of_char( const char* utfstr, int& byte, const char pre_c
//
// width == -1 はフォント幅の取得に失敗した場合
//
-void ARTICLE::set_width_of_char( const char* utfstr, int& byte, const char pre_char, const int width, const int width_wide, const int mode )
+void ARTICLE::set_width_of_char( const int code, const char pre_char, const int width, const int width_wide, const int mode )
{
- const int ucs2 = MISC::utf8toucs2( utfstr, byte );
- if( ! byte ) return;
- if( ucs2 >= UCS2_MAX ) return;
+ if( code <= 0 || code >= NUM_CHAR_MAX ) return;
// 半角モードの幅を厳密に求める場合
- if( byte == 1 && strict_of_char ){
+ if( code < 128 && strict_of_char ){
const int pre_char_num = ( int ) pre_char;
- if( pre_char_num < 128 ) width_of_char[ mode ][ ucs2 ].width[ pre_char_num ] = width;
+ if( pre_char_num < 128 ) width_of_char[ mode ][ code ].width[ pre_char_num ] = width;
}
// 全角モードの幅
- width_of_char[ mode ][ ucs2 ].width_wide = width_wide;
+ width_of_char[ mode ][ code ].width_wide = width_wide;
}
diff --git a/src/article/font.h b/src/article/font.h
index 81e59901..24e00677 100644
--- a/src/article/font.h
+++ b/src/article/font.h
@@ -10,18 +10,17 @@ namespace ARTICLE
void init_font();
// 登録された文字の幅を返す関数
- // utfstr : 入力文字 (UTF-8)
- // byte : 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す
+ // code : 入力文字 (コードポイント)
// pre_char : ひとつ前の文字 ( 前の文字が全角の場合は 0 )
// width : 半角モードでの幅
// width_wide : 全角モードでの幅
// mode : fontid.h で定義されているフォントのID
// 戻り値 : 登録されていればtrue
- bool get_width_of_char( const char* utfstr, int& byte, const char pre_char, int& width, int& width_wide, const int mode );
+ bool get_width_of_char( const int code, const char pre_char, int& width, int& width_wide, const int mode );
// 文字幅を登録する関数
// width == -1 はフォント幅の取得に失敗した場合
- void set_width_of_char( const char* utfstr, int& byte, const char pre_char, const int width, const int width_wide, const int mode );
+ void set_width_of_char( const int code, const char pre_char, const int width, const int width_wide, const int mode );
}
#endif
diff --git a/src/article/layouttree.cpp b/src/article/layouttree.cpp
index 4180ce17..48522e31 100644
--- a/src/article/layouttree.cpp
+++ b/src/article/layouttree.cpp
@@ -20,7 +20,7 @@
enum
{
- SIZE_OF_HEAP = 256 * 1024,
+ SIZE_OF_HEAP = 512 * 1024,
STEP_ID = 10,
STEP_SEPARATOR = 1,
@@ -310,6 +310,8 @@ void LayoutTree::append_node( DBTREE::NODE* node_header, const bool joint )
// 連結モード
// 本文ブロックだけ追加
if( joint ){
+ int classid = CORE::get_css_manager()->get_classid( "mes" );
+ create_layout_div( classid );
create_layout_br( m_last_dom_attr & CORE::DOMATTR_NOBR );
append_block( headinfo->block[ DBTREE::BLOCK_MES ], res_number, NULL, m_last_dom_attr );
}
@@ -396,6 +398,10 @@ void LayoutTree::append_block( DBTREE::NODE* block, const int res_number, IMGDAT
tmplayout = create_layout_text( tmpnode->text, &tmpnode->color_text, tmpnode->bold );
break;
+ case DBTREE::NODE_SP: // 半角スペース
+ tmplayout = create_layout_text( " ", &tmpnode->color_text, tmpnode->bold );
+ break;
+
case DBTREE::NODE_LINK:
tmplayout = create_layout_link( tmpnode->text, tmpnode->linkinfo->link,
&tmpnode->color_text, tmpnode->bold );
@@ -442,7 +448,8 @@ void LayoutTree::append_block( DBTREE::NODE* block, const int res_number, IMGDAT
break;
case DBTREE::NODE_HTAB: // 水平タブ
- tmplayout = create_layout_hspace( tmpnode->type );
+ if( m_show_multispace ) tmplayout = create_layout_hspace( tmpnode->type );
+ else tmplayout = create_layout_text( " ", &tmpnode->color_text, tmpnode->bold );
break;
}
diff --git a/src/article/preference.cpp b/src/article/preference.cpp
index 9b54a3e3..59416002 100644
--- a/src/article/preference.cpp
+++ b/src/article/preference.cpp
@@ -4,6 +4,7 @@
#include "dbtree/interface.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/misctime.h"
@@ -13,6 +14,7 @@
#include "cache.h"
#include "command.h"
+#include "global.h"
#include <list>
#include <set>
@@ -22,7 +24,7 @@ using namespace ARTICLE;
Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std::string command )
: SKELETON::PrefDiag( parent, url )
- ,m_label_name( false, "スレタイトル : ", DBTREE::article_subject( get_url() ) )
+ ,m_label_name( false, "スレタイトル : ", MISC::to_plain( DBTREE::article_subject( get_url() ) ) )
,m_label_url( false, "スレのURL : ", DBTREE:: url_readcgi( get_url(),0,0 ) )
,m_label_url_dat( false, "DATファイルのURL : ", DBTREE:: url_dat( get_url() ) )
,m_label_cache( false, "ローカルキャッシュパス : ", std::string() )
@@ -30,6 +32,8 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
,m_check_transpabone( "透明あぼ〜ん" )
,m_check_chainabone( "連鎖あぼ〜ん" )
,m_check_ageabone( "sage以外をあぼ〜ん" )
+ ,m_check_defnameabone( "デフォルト名無しをあぼ〜ん" )
+ ,m_check_noidabone( "ID無しをあぼ〜ん" )
,m_check_boardabone( "板レベルでのあぼ〜んを有効にする" )
,m_check_globalabone( "全体レベルでのあぼ〜んを有効にする" )
,m_label_since( false, "スレ立て日時 : ", std::string() )
@@ -73,15 +77,49 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
m_hbox_write.pack_start( m_label_write );
m_hbox_write.pack_start( m_bt_clear_post_history, Gtk::PACK_SHRINK );
+ m_label_charset.set_text( "エンコーディング:" );
+#if GTKMM_CHECK_VERSION(2,24,0)
+ m_combo_charset.append( MISC::charcode_to_cstr( CHARCODE_UTF8 ) );
+ m_combo_charset.append( MISC::charcode_to_cstr( CHARCODE_SJIS ) );
+ m_combo_charset.append( MISC::charcode_to_cstr( CHARCODE_EUCJP ) );
+ m_combo_charset.set_active_text( MISC::charcode_to_cstr( DBTREE::article_charcode( get_url() ) ) );
+#else
+ std::list< Glib::ustring > list_charset;
+ list_charset.push_back( MISC::charcode_to_cstr( CHARCODE_UTF8 ) );
+ list_charset.push_back( MISC::charcode_to_cstr( CHARCODE_SJIS ) );
+ list_charset.push_back( MISC::charcode_to_cstr( CHARCODE_EUCJP ) );
+ m_combo_charset.set_popdown_strings( list_charset );
+ m_combo_charset.get_entry()->set_text( MISC::charcode_to_cstr( DBTREE::article_charcode( get_url() ) ) );
+ m_combo_charset.get_entry()->set_editable( false );
+ m_combo_charset.set_value_in_list( false );
+#endif
+
+ m_hbox_since.pack_start( m_label_since );
+ m_hbox_since.pack_start( m_label_charset, Gtk::PACK_SHRINK );
+ m_hbox_since.pack_start( m_combo_charset, Gtk::PACK_SHRINK );
+
+
+ // 最大レス数
+ const int max_res = DBTREE::article_number_max( get_url() );
+ m_label_maxres.set_text( "最大レス数 (0 : 未設定):" );
+ m_spin_maxres.set_range( 0, CONFIG::get_max_resnumber() );
+ m_spin_maxres.set_increments( 1, 1 );
+ m_spin_maxres.set_value( max_res );
+ m_spin_maxres.set_sensitive( true );
+
+ m_hbox_size.pack_start( m_label_size );
+ m_hbox_size.pack_start( m_label_maxres, Gtk::PACK_SHRINK );
+ m_hbox_size.pack_start( m_spin_maxres, Gtk::PACK_SHRINK );
+
m_vbox_info.set_border_width( 16 );
m_vbox_info.set_spacing( 8 );
m_vbox_info.pack_start( m_label_name, Gtk::PACK_SHRINK );
m_vbox_info.pack_start( m_label_url, Gtk::PACK_SHRINK );
m_vbox_info.pack_start( m_label_url_dat, Gtk::PACK_SHRINK );
m_vbox_info.pack_start( m_label_cache, Gtk::PACK_SHRINK );
- m_vbox_info.pack_start( m_label_size, Gtk::PACK_SHRINK );
+ m_vbox_info.pack_start( m_hbox_size, Gtk::PACK_SHRINK );
- m_vbox_info.pack_start( m_label_since, Gtk::PACK_SHRINK );
+ m_vbox_info.pack_start( m_hbox_since, Gtk::PACK_SHRINK );
m_vbox_info.pack_start( m_hbox_modified, Gtk::PACK_SHRINK );
m_vbox_info.pack_start( m_hbox_write, Gtk::PACK_SHRINK );
@@ -104,6 +142,12 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
// ageあぼーん
m_check_ageabone.set_active( DBTREE::get_abone_age( get_url() ) );
+ // デフォルト名無しあぼーん
+ m_check_defnameabone.set_active( DBTREE::get_abone_default_name( get_url() ) );
+
+ // ID無しあぼーん
+ m_check_noidabone.set_active( DBTREE::get_abone_noid( get_url() ) );
+
// 板レベルあぼーん
m_check_boardabone.set_active( DBTREE::get_abone_board( get_url() ) );
@@ -116,6 +160,8 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
m_vbox_abone.pack_start( m_check_transpabone, Gtk::PACK_SHRINK );
m_vbox_abone.pack_start( m_check_chainabone, Gtk::PACK_SHRINK );
m_vbox_abone.pack_start( m_check_ageabone, Gtk::PACK_SHRINK );
+ m_vbox_abone.pack_start( m_check_defnameabone, Gtk::PACK_SHRINK );
+ m_vbox_abone.pack_start( m_check_noidabone, Gtk::PACK_SHRINK );
m_vbox_abone.pack_start( m_check_boardabone, Gtk::PACK_SHRINK );
m_vbox_abone.pack_start( m_check_globalabone, Gtk::PACK_SHRINK );
@@ -201,15 +247,14 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
m_notebook.append_page( m_notebook_abone, "あぼ〜ん設定" );
get_vbox()->pack_start( m_notebook );
- set_title( "「" + DBTREE::article_subject( get_url() ) + "」のプロパティ" );
+ set_title( "「" + MISC::to_plain( DBTREE::article_modified_subject( get_url() ) ) + "」のプロパティ" );
resize( 600, 400 );
show_all_children();
if( command == "show_abone" ) m_notebook.set_current_page( page_abone );
}
-Preferences::~Preferences() noexcept
-{}
+Preferences::~Preferences() noexcept = default;
//
@@ -242,8 +287,26 @@ void Preferences::slot_ok_clicked()
DBTREE::reset_abone( get_url(), list_id, list_name, list_word, list_regex, vec_abone_res
, m_check_transpabone.get_active(), m_check_chainabone.get_active(), m_check_ageabone.get_active(),
+ m_check_defnameabone.get_active(), m_check_noidabone.get_active(),
m_check_boardabone.get_active(), m_check_globalabone.get_active() );
+ //最大レス数
+ DBTREE::article_set_number_max( get_url(), m_spin_maxres.get_value_as_int() );
+
+ // charset
+#if GTKMM_CHECK_VERSION(2,24,0)
+ std::string tmpcharset = m_combo_charset.get_active_text();
+#else
+ std::string tmpcharset = m_combo_charset.get_entry()->get_text();
+#endif
+ CharCode tmpcharcode = MISC::charcode_from_cstr( tmpcharset.c_str() );
+ if( tmpcharcode != DBTREE::article_charcode( get_url() ) ){
+ // charcodeを更新
+ DBTREE::article_set_charcode( get_url(), tmpcharcode );
+ // Viewが開かれていない場合があるのでここでNodeTreeを削除する
+ DBTREE::article_clear_nodetree( get_url() );
+ }
+
// viewの再レイアウト
CORE::core_set_command( "relayout_article", get_url() );
}
@@ -274,5 +337,5 @@ void Preferences::slot_clear_post_history()
CORE::core_set_command( "redraw_article" );
// BoardViewの行を更新
- CORE::core_set_command( "update_board_item", DBTREE::url_subject( get_url() ), DBTREE::article_id( get_url() ) );
+ CORE::core_set_command( "update_board_item", DBTREE::url_boardbase( get_url() ), DBTREE::article_id( get_url() ) );
}
diff --git a/src/article/preference.h b/src/article/preference.h
index 4e79e0c4..069161e2 100644
--- a/src/article/preference.h
+++ b/src/article/preference.h
@@ -3,9 +3,11 @@
#ifndef _ARTICLE_PREFERENCES_H
#define _ARTICLE_PREFERENCES_H
+#include "gtkmmversion.h"
#include "skeleton/prefdiag.h"
#include "skeleton/editview.h"
#include "skeleton/label_entry.h"
+#include "skeleton/spinbutton.h"
namespace ARTICLE
{
@@ -21,6 +23,20 @@ namespace ARTICLE
SKELETON::LabelEntry m_label_cache;
SKELETON::LabelEntry m_label_size;
+ Gtk::HBox m_hbox_size;
+
+ // 最大レス数
+ Gtk::Label m_label_maxres;
+ SKELETON::SpinButton m_spin_maxres;
+
+ // エンコーディング
+ Gtk::Label m_label_charset;
+#if GTKMM_CHECK_VERSION(2,24,0)
+ Gtk::ComboBoxText m_combo_charset;
+#else
+ Gtk::Combo m_combo_charset;
+#endif
+
// あぼーん
Gtk::VBox m_vbox_abone;
Gtk::Notebook m_notebook_abone;
@@ -39,12 +55,19 @@ namespace ARTICLE
// ageあぼーん
Gtk::CheckButton m_check_ageabone;
+ // ageあぼーん
+ Gtk::CheckButton m_check_defnameabone;
+
+ // ageあぼーん
+ Gtk::CheckButton m_check_noidabone;
+
// 板レベルでのあぼーん
Gtk::CheckButton m_check_boardabone;
// 全体レベルでのあぼーん
Gtk::CheckButton m_check_globalabone;
+ Gtk::HBox m_hbox_since;
SKELETON::LabelEntry m_label_since;
// 最終更新日時
diff --git a/src/article/toolbar.cpp b/src/article/toolbar.cpp
index d73572e9..1031fede 100644
--- a/src/article/toolbar.cpp
+++ b/src/article/toolbar.cpp
@@ -50,6 +50,9 @@ ArticleToolBar::ArticleToolBar() :
}
+ArticleToolBar::~ArticleToolBar() noexcept = default;
+
+
//
// タブが切り替わった時にDragableNoteBook::set_current_toolbar()から呼び出される( Viewの情報を取得する )
//
diff --git a/src/article/toolbar.h b/src/article/toolbar.h
index 757bff6a..9893436b 100644
--- a/src/article/toolbar.h
+++ b/src/article/toolbar.h
@@ -33,7 +33,7 @@ namespace ARTICLE
public:
ArticleToolBar();
- ~ArticleToolBar() noexcept {}
+ ~ArticleToolBar() noexcept;
// タブが切り替わった時に呼び出される( Viewの情報を取得する )
void set_view( SKELETON::View * view ) override;
diff --git a/src/article/toolbarsearch.cpp b/src/article/toolbarsearch.cpp
index 5aae5304..92c3383e 100644
--- a/src/article/toolbarsearch.cpp
+++ b/src/article/toolbarsearch.cpp
@@ -37,6 +37,9 @@ SearchToolBar::SearchToolBar() :
}
+SearchToolBar::~SearchToolBar() noexcept = default;
+
+
//
// ボタンのパッキング
//
diff --git a/src/article/toolbarsearch.h b/src/article/toolbarsearch.h
index f83f15d2..b8c88577 100644
--- a/src/article/toolbarsearch.h
+++ b/src/article/toolbarsearch.h
@@ -26,7 +26,7 @@ namespace ARTICLE
public:
SearchToolBar();
- ~SearchToolBar() noexcept {}
+ ~SearchToolBar() noexcept;
// タブが切り替わった時に呼び出される( Viewの情報を取得する )
void set_view( SKELETON::View * view ) override;
diff --git a/src/article/toolbarsimple.cpp b/src/article/toolbarsimple.cpp
index fceb2e29..11fb6e3d 100644
--- a/src/article/toolbarsimple.cpp
+++ b/src/article/toolbarsimple.cpp
@@ -24,6 +24,9 @@ ArticleToolBarSimple::ArticleToolBarSimple() :
}
+ArticleToolBarSimple::~ArticleToolBarSimple() noexcept = default;
+
+
//
// ボタンのパッキング
//
diff --git a/src/article/toolbarsimple.h b/src/article/toolbarsimple.h
index 56257e1c..d2f6c2fc 100644
--- a/src/article/toolbarsimple.h
+++ b/src/article/toolbarsimple.h
@@ -14,7 +14,7 @@ namespace ARTICLE
public:
ArticleToolBarSimple();
- ~ArticleToolBarSimple() noexcept {}
+ ~ArticleToolBarSimple() noexcept;
protected:
diff --git a/src/articleitemmenupref.h b/src/articleitemmenupref.h
index 86d6926f..9f9bd41b 100644
--- a/src/articleitemmenupref.h
+++ b/src/articleitemmenupref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
ArticleItemMenuPref( Gtk::Window* parent, const std::string& url );
- ~ArticleItemMenuPref() noexcept {}
+ ~ArticleItemMenuPref() noexcept = default;
private:
diff --git a/src/articleitempref.h b/src/articleitempref.h
index 92ca34d7..200a29e6 100644
--- a/src/articleitempref.h
+++ b/src/articleitempref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
ArticleItemPref( Gtk::Window* parent, const std::string& url );
- ~ArticleItemPref() noexcept {}
+ ~ArticleItemPref() noexcept = default;
private:
diff --git a/src/bbslist/addetcdialog.cpp b/src/bbslist/addetcdialog.cpp
index a5c63a73..d3994734 100644
--- a/src/bbslist/addetcdialog.cpp
+++ b/src/bbslist/addetcdialog.cpp
@@ -49,3 +49,6 @@ AddEtcDialog::AddEtcDialog( const bool move, const std::string& url, const std::
show_all_children();
}
+
+
+AddEtcDialog::~AddEtcDialog() noexcept = default;
diff --git a/src/bbslist/addetcdialog.h b/src/bbslist/addetcdialog.h
index 69121de5..f6c16c7a 100644
--- a/src/bbslist/addetcdialog.h
+++ b/src/bbslist/addetcdialog.h
@@ -24,6 +24,7 @@ namespace BBSLIST
public:
AddEtcDialog( const bool move, const std::string& url, const std::string& _name, const std::string& _id, const std::string& _passwd );
+ ~AddEtcDialog() noexcept;
std::string get_name() const { return m_entry_name.get_text(); }
std::string get_url() const { return m_entry_url.get_text(); }
diff --git a/src/bbslist/bbslistadmin.cpp b/src/bbslist/bbslistadmin.cpp
index 940f0175..d98b10b2 100644
--- a/src/bbslist/bbslistadmin.cpp
+++ b/src/bbslist/bbslistadmin.cpp
@@ -247,9 +247,12 @@ void BBSListAdmin::command_local( const COMMAND_ARGS& command )
// 板のアイコン表示を更新
else if( command.command == "toggle_boardicon" ) view->set_command( "toggle_boardicon", command.arg1 );
+ }
- // URLを選択
- else if( command.command == "select_item" ) view->set_command( "select_item", command.arg1 );
+ // URLを選択
+ if( command.command == "select_item" ){
+ view = get_current_view();
+ if( view ) view->set_command( "select_item", command.arg1 );
}
}
diff --git a/src/bbslist/bbslistviewbase.cpp b/src/bbslist/bbslistviewbase.cpp
index a3c7bc8a..7f6bf6e3 100644
--- a/src/bbslist/bbslistviewbase.cpp
+++ b/src/bbslist/bbslistviewbase.cpp
@@ -644,7 +644,7 @@ void BBSListViewBase::redraw_view()
//
// 色やフォントなどの変更
//
-void BBSListViewBase::relayout()
+void BBSListViewBase::relayout( const bool completely )
{
m_treeview.init_color( COLOR_CHAR_BBS, COLOR_BACK_BBS, COLOR_BACK_BBS_EVEN );
m_treeview.init_font( CONFIG::get_fontname( FONT_BBS ) );
@@ -1158,23 +1158,23 @@ bool BBSListViewBase::slot_motion_notify( GdkEventMotion* event )
const int mrg = 16; // アイコンの横幅。計算するのが面倒だったのでとりあえず
Gtk::TreeModel::Row row = m_treeview.get_row( path );
- Glib::ustring subject = row[ m_columns.m_name ];
- Glib::ustring url = row[ m_columns.m_url ];
+ const Glib::ustring ustr_subject = row[ m_columns.m_name ];
+ const Glib::ustring ustr_url = row[ m_columns.m_url ];
int type = row[ m_columns.m_type ];
- m_treeview.reset_pre_popupurl( url );
+ m_treeview.reset_pre_popupurl( ustr_url.raw() );
// 画像ポップアップ
if( type == TYPE_IMAGE ){
m_treeview.hide_tooltip();
- if( DBIMG::get_type_ext( url ) != DBIMG::T_UNKNOWN && DBIMG::get_code( url ) != HTTP_INIT ){
+ if( DBIMG::get_type_ext( ustr_url.raw() ) != DBIMG::T_UNKNOWN && DBIMG::get_code( ustr_url.raw() ) != HTTP_INIT ){
- if( m_treeview.pre_popup_url() != url ){
+ if( m_treeview.pre_popup_url() != ustr_url.raw() ){
- SKELETON::View* view = CORE::ViewFactory( CORE::VIEW_IMAGEPOPUP, url );
- m_treeview.show_popup( url, view );
+ SKELETON::View* view = CORE::ViewFactory( CORE::VIEW_IMAGEPOPUP, ustr_url.raw() );
+ m_treeview.show_popup( ustr_url.raw(), view );
}
}
else m_treeview.hide_popup();
@@ -1188,7 +1188,7 @@ bool BBSListViewBase::slot_motion_notify( GdkEventMotion* event )
Gdk::Rectangle rect;
m_treeview.get_cell_area( path, *column, rect );
m_treeview.set_tooltip_min_width( rect.get_width() - mrg );
- m_treeview.set_str_tooltip( subject );
+ m_treeview.set_str_tooltip( ustr_subject.raw() );
}
}
else{
@@ -1470,7 +1470,7 @@ void BBSListViewBase::add_newetcboard( const bool move, // true なら編集モ
}
// http が無ければ付ける
- if( url.find( "http://" ) != 0 && url.find( "https://" ) != 0 ) url = "http://" + url;
+ if( url.find( "://" ) == std::string::npos ) url = "http://" + url;
// .htmlを取り除く
JDLIB::Regex regex;
@@ -1606,9 +1606,21 @@ void BBSListViewBase::slot_copy_title_url()
if( m_path_selected.empty() ) return;
const std::string url = path2url( m_path_selected );
- const std::string name = path2name( m_path_selected );
+ std::string name;
- MISC::CopyClipboard( name + '\n' + url );
+ int type = path2type( m_path_selected );
+ switch( type ){
+ case TYPE_THREAD:
+ case TYPE_THREAD_UPDATE:
+ case TYPE_THREAD_OLD:
+ name = MISC::to_plain( DBTREE::article_subject( url ) );
+ break;
+
+ default:
+ name = path2name( m_path_selected );
+ }
+
+ MISC::CopyClipboard( name + '\n' + url + '\n' );
}
@@ -1711,7 +1723,7 @@ void BBSListViewBase::check_update_dir( const bool root, const bool open )
if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE ) CORE::get_checkupdate_manager()->push_back( DBTREE::url_dat( url ), open );
else if( CONFIG::get_check_update_board() && ( type == TYPE_BOARD || type == TYPE_BOARD_UPDATE ) )
- CORE::get_checkupdate_manager()->push_back( DBTREE::url_subject( url ), open );
+ CORE::get_checkupdate_manager()->push_back( DBTREE::url_boardbase( url ), open );
}
@@ -1812,7 +1824,7 @@ void BBSListViewBase::slot_preferences_board()
if( m_path_selected.empty() ) return;
std::string url = path2url( m_path_selected );
- SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( url ) );
+ SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( get_parent_win(), CORE::PREFDIAG_BOARD, DBTREE::url_boardbase( url ) );
pref->run();
delete pref;
}
@@ -1888,15 +1900,16 @@ void BBSListViewBase::slot_row_col( const Gtk::TreeModel::iterator&, const Gtk::
//
bool BBSListViewBase::open_row( Gtk::TreePath& path, const bool tab )
{
- if( ! m_treeview.get_row( path ) ) return false;
+ const Gtk::TreeModel::Row row = m_treeview.get_row( path );
+ if( ! row ) return false;
std::string str_tab = "false";
if( tab ) str_tab = "opentab";
const std::string str_mode = "";
- const Glib::ustring url = path2url( path );
- const int type = path2type( path );
+ const std::string url = row2url( row );
+ const int type = row2type( row );
if( type != TYPE_DIR && url.empty() ) return false;
@@ -1904,7 +1917,7 @@ bool BBSListViewBase::open_row( Gtk::TreePath& path, const bool tab )
case TYPE_BOARD:
case TYPE_BOARD_UPDATE:
- CORE::core_set_command( "open_board", DBTREE::url_subject( url ), str_tab, str_mode );
+ CORE::core_set_command( "open_board", url, str_tab, str_mode );
break;
case TYPE_THREAD_OLD:
@@ -1912,7 +1925,7 @@ bool BBSListViewBase::open_row( Gtk::TreePath& path, const bool tab )
// fallthrough
case TYPE_THREAD:
case TYPE_THREAD_UPDATE:
- CORE::core_set_command( "open_article", DBTREE::url_dat( url ), str_tab, str_mode );
+ CORE::core_set_command( "open_article", url, str_tab, str_mode );
break;
case TYPE_IMAGE:
@@ -1979,16 +1992,14 @@ void BBSListViewBase::open_selected_rows()
for( ; it != list_it.end(); ++it ){
Gtk::TreeModel::Row row = *( *it );
- Gtk::TreePath path = GET_PATH( row );
- int type = path2type( path );
- std::string url = path2url( path );
+ int type = row2type( row );
+ std::string url = row2url( row );
switch( type ){
case TYPE_BOARD:
case TYPE_BOARD_UPDATE:
- url = DBTREE::url_subject( url );
if( !list_url_board.empty() ) list_url_board += " ";
list_url_board += url;
break;
@@ -1996,7 +2007,6 @@ void BBSListViewBase::open_selected_rows()
case TYPE_THREAD:
case TYPE_THREAD_UPDATE:
case TYPE_THREAD_OLD:
- url = DBTREE::url_dat( url );
if( !list_url_article.empty() ) list_url_article += " ";
list_url_article += url;
break;
@@ -2025,14 +2035,13 @@ void BBSListViewBase::checkupdate_selected_rows( const bool open )
for( ; it != list_it.end(); ++it ){
Gtk::TreeModel::Row row = *( *it );
- Gtk::TreePath path = GET_PATH( row );
- int type = path2type( path );
- std::string url = path2url( path );
+ int type = row2type( row );
+ std::string url = row2url( row );
- if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE ) CORE::get_checkupdate_manager()->push_back( DBTREE::url_dat( url ), open );
+ if( type == TYPE_THREAD || type == TYPE_THREAD_UPDATE ) CORE::get_checkupdate_manager()->push_back( url, open );
else if( CONFIG::get_check_update_board() && ( type == TYPE_BOARD || type == TYPE_BOARD_UPDATE ) )
- CORE::get_checkupdate_manager()->push_back( DBTREE::url_subject( url ), open );
+ CORE::get_checkupdate_manager()->push_back( url, open );
}
}
@@ -2060,32 +2069,21 @@ void BBSListViewBase::slot_sort( const int mode )
//
// path -> url 変換
//
-Glib::ustring BBSListViewBase::path2rawurl( const Gtk::TreePath& path )
+std::string BBSListViewBase::path2rawurl( const Gtk::TreePath& path )
{
- Gtk::TreeModel::Row row = m_treeview.get_row( path );
- if( !row ) return Glib::ustring();
- Glib::ustring url = row[ m_columns.m_url ];
- return url;
+ const Gtk::TreeModel::Row row = m_treeview.get_row( path );
+ return row2url( row );
}
// 移転をチェックするバージョン
-Glib::ustring BBSListViewBase::path2url( const Gtk::TreePath& path )
+std::string BBSListViewBase::path2url( const Gtk::TreePath& path )
{
- Gtk::TreeModel::Row row = m_treeview.get_row( path );
- if( !row ) return Glib::ustring();
+ const Gtk::TreeModel::Row row = m_treeview.get_row( path );
+ std::string url = row2url( row );
- Glib::ustring url = row[ m_columns.m_url ];
- if( url.empty() ) return url;
-
- // 移転があったら url を最新のものに変換しておく
- int type = path2type( path );
- switch( type ){
-
- case TYPE_BOARD:
- case TYPE_BOARD_UPDATE:
- url = DBTREE::url_boardbase( url );
- break;
+ // url を最新のものに変換しておく
+ switch( row2type( row ) ){
case TYPE_THREAD:
case TYPE_THREAD_UPDATE:
@@ -2104,29 +2102,12 @@ Glib::ustring BBSListViewBase::path2url( const Gtk::TreePath& path )
// 板の場合は boardbase
// スレの場合は dat 型のアドレスを返す
//
-Glib::ustring BBSListViewBase::row2url( const Gtk::TreeModel::Row& row )
+std::string BBSListViewBase::row2url( const Gtk::TreeModel::Row& row )
{
- if( ! row ) return Glib::ustring();
-
- Glib::ustring url = row[ m_columns.m_url ];
- if( url.empty() ) return url;
-
- // 移転があったら url を最新のものに変換しておく
- int type = row2type( row );
- switch( type ){
-
- case TYPE_BOARD:
- case TYPE_BOARD_UPDATE:
- url = DBTREE::url_boardbase( url );
- break;
-
- case TYPE_THREAD:
- case TYPE_THREAD_UPDATE:
- case TYPE_THREAD_OLD:
- url = DBTREE::url_dat( url );
- break;
- }
-
+ std::string url;
+ if( ! row ) return url;
+ const Glib::ustring ustr_url = row[ m_columns.m_url ];
+ url = ustr_url.raw();
return url;
}
@@ -2135,23 +2116,34 @@ Glib::ustring BBSListViewBase::row2url( const Gtk::TreeModel::Row& row )
//
// path -> name 変換
//
-Glib::ustring BBSListViewBase::path2name( const Gtk::TreePath& path )
+std::string BBSListViewBase::path2name( const Gtk::TreePath& path )
{
- Gtk::TreeModel::Row row = m_treeview.get_row( path );
- if( !row ) return Glib::ustring();
- return row[ m_columns.m_name ];
+ const Gtk::TreeModel::Row row = m_treeview.get_row( path );
+ return row2name( row );
}
+//
+// row -> name 変換
+//
+std::string BBSListViewBase::row2name( const Gtk::TreeModel::Row& row )
+{
+ std::string name;
+ if( !row ) return name;
+ const Glib::ustring ustr_name = row[ m_columns.m_name ];
+ name = ustr_name.raw();
+ return name;
+}
+
+
//
// path -> type 変換
//
int BBSListViewBase::path2type( const Gtk::TreePath& path )
{
- Gtk::TreeModel::Row row = m_treeview.get_row( path );
- if( !row ) return TYPE_UNKNOWN;
- return row[ m_columns.m_type ];
+ const Gtk::TreeModel::Row row = m_treeview.get_row( path );
+ return row2type( row );
}
@@ -2165,16 +2157,6 @@ int BBSListViewBase::row2type( const Gtk::TreeModel::Row& row )
}
-//
-// row -> name 変換
-//
-Glib::ustring BBSListViewBase::row2name( const Gtk::TreeModel::Row& row )
-{
- if( !row ) return Glib::ustring();
- return row[ m_columns.m_name ];
-}
-
-
//
// row -> dirid 変換
//
@@ -2351,7 +2333,7 @@ void BBSListViewBase::update_urls()
for( ; ! it.end(); ++it ){
Gtk::TreeModel::Row row = *it;
- const Glib::ustring url = row[ m_columns.m_url ];
+ const Glib::ustring ustr_url = row[ m_columns.m_url ];
const int type = row[ m_columns.m_type ];
#ifdef _DEBUG
@@ -2364,12 +2346,12 @@ void BBSListViewBase::update_urls()
case TYPE_BOARD: // 板
case TYPE_BOARD_UPDATE:
- url_new = DBTREE::url_boardbase( url );
- if( url != url_new ){
+ url_new = DBTREE::url_boardbase( ustr_url.raw() );
+ if( ustr_url.raw() != url_new ){
updated = true;
row[ m_columns.m_url ] = url_new;
#ifdef _DEBUG
- std::cout << url << " -> " << url_new << std::endl;
+ std::cout << ustr_url << " -> " << url_new << std::endl;
#endif
}
@@ -2377,19 +2359,19 @@ void BBSListViewBase::update_urls()
break;
case TYPE_VBOARD:
- m_set_board.insert( url );
+ m_set_board.insert( ustr_url.raw() );
break;
case TYPE_THREAD: // スレ
case TYPE_THREAD_UPDATE:
case TYPE_THREAD_OLD:
- url_new = DBTREE::url_dat( url );
- if( url != url_new ){
+ url_new = DBTREE::url_dat( ustr_url.raw() );
+ if( ustr_url.raw() != url_new ){
updated = true;
row[ m_columns.m_url ] = url_new;
#ifdef _DEBUG
- std::cout << url << " -> " << url_new << std::endl;
+ std::cout << ustr_url << " -> " << url_new << std::endl;
#endif
}
@@ -2397,7 +2379,7 @@ void BBSListViewBase::update_urls()
break;
case TYPE_IMAGE:
- m_set_image.insert( url );
+ m_set_image.insert( ustr_url.raw() );
break;
}
}
@@ -2442,7 +2424,7 @@ void BBSListViewBase::toggle_articleicon( const std::string& url )
if( type_row == TYPE_THREAD || type_row == TYPE_THREAD_UPDATE || type_row == TYPE_THREAD_OLD ){
- if( url == url_row ){
+ if( url == url_row.raw() ){
#ifdef _DEBUG
std::cout << "hit " << url << " == " << url_row << std::endl;
std::cout << row2name( row ) << std::endl;
@@ -2491,7 +2473,7 @@ void BBSListViewBase::toggle_boardicon( const std::string& url )
if( type_row == TYPE_BOARD || type_row == TYPE_BOARD_UPDATE ){
- if( url_boardbase == url_row ){
+ if( url_boardbase == url_row.raw() ){
#ifdef _DEBUG
std::cout << "hit " << url_boardbase << " == " << url_row << std::endl;
std::cout << row2name( row ) << std::endl;
@@ -2517,14 +2499,18 @@ void BBSListViewBase::select_item( const std::string& url )
if( ! m_ready_tree ) return;
if( m_treestore->children().empty() ) return;
- std::string url_item( url );
+ std::string url_item;
- if( m_set_thread.find( url_item ) != m_set_thread.end()
- || m_set_image.find( url_item ) != m_set_image.end()){
+ if( m_set_thread.find( url ) != m_set_thread.end()
+ || m_set_image.find( url ) != m_set_image.end()){
// スレまたは画像の場合
+ url_item = url;
}
else {
// 板の場合
+ if( get_url() == URL_HISTTHREADVIEW || get_url() == URL_HISTCLOSEVIEW ||
+ get_url() == URL_HISTCLOSEIMGVIEW ) return;
+
url_item = DBTREE::url_boardbase( url );
// 未登録の画像などで、板が見つからない場合は処理しない
@@ -2545,9 +2531,10 @@ void BBSListViewBase::select_item( const std::string& url )
for( ; ! it.end(); ++it ){
Gtk::TreeModel::Row row = *it;
- Gtk::TreePath path = GET_PATH( row );
+ const Glib::ustring ustr_url = row[ m_columns.m_url ];
- if( url_item == row[ m_columns.m_url ] || url_item == path2url( path ) ){
+ if( url_item == ustr_url.raw() ){
+ path = GET_PATH( row );
// 最初に見つかったものにフォーカスする
if( m_treeview.is_expand( path ) ){
@@ -2593,7 +2580,7 @@ void BBSListViewBase::replace_thread( const std::string& url, const std::string&
const std::string urldat_new = DBTREE::url_dat( url_new );
if( urldat_new.empty() ) return;
- const std::string name_new = DBTREE::article_subject( urldat_new );
+ const std::string name_new = MISC::to_plain( DBTREE::article_modified_subject( urldat_new ) );
if( name_new.empty() ) return;
bool show_diag = CONFIG::show_diag_replace_favorite();
@@ -2601,8 +2588,7 @@ void BBSListViewBase::replace_thread( const std::string& url, const std::string&
if( ! show_diag && mode == REPLACE_NEXT_NO ) return;
const std::string urldat = DBTREE::url_dat( url );
- const std::string urlcgi = DBTREE::url_readcgi( url, 0, 0 );
- const std::string name_old = MISC::remove_space( DBTREE::article_subject( urldat ) );
+ const std::string name_old = MISC::to_plain( DBTREE::article_modified_subject( urldat ) );
int type = TYPE_THREAD;
const int status = DBTREE::article_status( urldat_new );
@@ -2619,7 +2605,7 @@ void BBSListViewBase::replace_thread( const std::string& url, const std::string&
for( ; ! it.end(); ++it ){
Gtk::TreeModel::Row row = *it;
- const Glib::ustring url_row = row[ m_columns.m_url ];
+ const Glib::ustring ustr_url = row[ m_columns.m_url ];
switch( row[ m_columns.m_type ] ){
@@ -2627,7 +2613,7 @@ void BBSListViewBase::replace_thread( const std::string& url, const std::string&
case TYPE_THREAD_UPDATE:
case TYPE_THREAD_OLD:
- if( urldat == url_row || urlcgi == url_row ){
+ if( urldat == ustr_url.raw() ){
if( show_diag ){
@@ -2672,11 +2658,11 @@ void BBSListViewBase::replace_thread( const std::string& url, const std::string&
// 名前が古いものであったら更新
// 手動で変更されていたらそのまま
- const Glib::ustring name_row = row[ m_columns.m_name ];
+ const Glib::ustring ustr_name = row[ m_columns.m_name ];
#ifdef _DEBUG
- std::cout << "name_row = " << name_row << std::endl;
+ std::cout << "name_row = " << ustr_name << std::endl;
#endif
- if( MISC::remove_space( name_row ) == name_old ){
+ if( ustr_name.raw() == name_old ){
#ifdef _DEBUG
std::cout << "replace name\n";
#endif
@@ -2718,9 +2704,6 @@ void BBSListViewBase::replace_thread( const std::string& url, const std::string&
//
void BBSListViewBase::exec_search()
{
- JDLIB::Regex regex_name;
- JDLIB::Regex regex_url;
-
CORE::core_set_command( "set_info", "", "" );
std::string query = get_search_query();
@@ -2753,13 +2736,15 @@ void BBSListViewBase::exec_search()
const bool newline_name = true; // . に改行をマッチさせない
const bool usemigemo_name = true; // migemo使用
const bool wchar_name = true; // 全角半角の区別をしない
- regex_name.compile( query, icase_name, newline_name, usemigemo_name, wchar_name );
+ JDLIB::RegexPattern regex_name( query, icase_name, newline_name, usemigemo_name, wchar_name );
const bool icase_url = true; // 大文字小文字区別しない
const bool newline_url = true;
const bool usemigemo_url = false;
const bool wchar_url = false;
- regex_url.compile( query, icase_url, newline_url, usemigemo_url, wchar_url );
+ JDLIB::RegexPattern regex_url( query, icase_url, newline_url, usemigemo_url, wchar_url );
+
+ JDLIB::Regex regex;
bool hit = false;
for(;;){
@@ -2790,11 +2775,11 @@ void BBSListViewBase::exec_search()
else path = m_treeview.prev_path( path, false );
}
- Glib::ustring name = path2name( path );
- Glib::ustring url = path2url( path );
+ const std::string name = path2name( path );
+ const std::string url = path2url( path );
const size_t offset = 0;
- if( regex_name.exec( name, offset ) || regex_url.exec( url, offset ) ) hit = true;
+ if( regex.match( regex_name, name, offset ) || regex.match( regex_url, url, offset ) ) hit = true;
// 一周したら終わり
if( path == path_start ) break;
@@ -3061,7 +3046,7 @@ void BBSListViewBase::remove_item( const std::string& url )
for( ; ! it.end(); ++it ){
Gtk::TreeModel::Row row = *it;
- const Glib::ustring url = row[ m_columns.m_url ];
+ const Glib::ustring ustr_url = row[ m_columns.m_url ];
const int type = row[ m_columns.m_type ];
switch( type ){
@@ -3075,7 +3060,7 @@ void BBSListViewBase::remove_item( const std::string& url )
case TYPE_IMAGE: // 画像
- if( url == url_target ){
+ if( ustr_url.raw() == url_target ){
#ifdef _DEBUG
std::cout << "hit " << url << " == " << url_target << std::endl;
std::cout << row2name( row ) << std::endl;
diff --git a/src/bbslist/bbslistviewbase.h b/src/bbslist/bbslistviewbase.h
index 183375e0..06025438 100644
--- a/src/bbslist/bbslistviewbase.h
+++ b/src/bbslist/bbslistviewbase.h
@@ -142,22 +142,22 @@ namespace BBSLIST
int row2type( const Gtk::TreeModel::Row& row );
// row -> name 変換
- Glib::ustring row2name( const Gtk::TreeModel::Row& row );
+ std::string row2name( const Gtk::TreeModel::Row& row );
// row -> url 変換
// 板の場合は boardbase
// スレの場合は dat 型のアドレスを返す
- Glib::ustring row2url( const Gtk::TreeModel::Row& row );
+ std::string row2url( const Gtk::TreeModel::Row& row );
// row -> dirid 変換
size_t row2dirid( const Gtk::TreeModel::Row& row );
// path からその行の名前を取得
- Glib::ustring path2name( const Gtk::TreePath& path );
+ std::string path2name( const Gtk::TreePath& path );
// path からその行のURLを取得
- Glib::ustring path2rawurl( const Gtk::TreePath& path );
- Glib::ustring path2url( const Gtk::TreePath& path ); // 移転をチェックするバージョン
+ std::string path2rawurl( const Gtk::TreePath& path );
+ std::string path2url( const Gtk::TreePath& path ); // 移転をチェックするバージョン
// url で指定した項目を削除
void remove_item( const std::string& url );
@@ -194,7 +194,7 @@ namespace BBSLIST
// 親ウィンドウをセット
void set_parent_win( Gtk::Window* parent_win ) override;
- std::string url_for_copy() override { return {}; }
+ std::string url_for_copy() const override { return {}; }
bool set_command( const std::string& command,
const std::string& arg1 = {},
@@ -207,7 +207,7 @@ namespace BBSLIST
void stop() override;
void redraw_view() override;
- void relayout() override; // 色やフォントなどの変更
+ void relayout( const bool completely = false ) override; // 色やフォントなどの変更
void focus_view() override;
void focus_out() override;
void close_view() override;
diff --git a/src/bbslist/columns.cpp b/src/bbslist/columns.cpp
index 707dd408..d4935a9c 100644
--- a/src/bbslist/columns.cpp
+++ b/src/bbslist/columns.cpp
@@ -19,8 +19,7 @@ TreeColumns::TreeColumns()
: SKELETON::EditColumns()
{}
-TreeColumns::~TreeColumns() noexcept
-{}
+TreeColumns::~TreeColumns() noexcept = default;
void TreeColumns::setup_row( Gtk::TreeModel::Row& row,
const Glib::ustring url, const Glib::ustring name, const Glib::ustring data,
diff --git a/src/bbslist/editlistwin.cpp b/src/bbslist/editlistwin.cpp
index 650ea439..44f3e98b 100644
--- a/src/bbslist/editlistwin.cpp
+++ b/src/bbslist/editlistwin.cpp
@@ -74,6 +74,9 @@ EditListWin::EditListWin( const std::string& url, Glib::RefPtr< Gtk::TreeStore >
}
+EditListWin::~EditListWin() noexcept = default;
+
+
void EditListWin::clock_in()
{
if( m_selectview ) m_selectview->clock_in();
diff --git a/src/bbslist/editlistwin.h b/src/bbslist/editlistwin.h
index 0f9b0bc3..30029ca8 100644
--- a/src/bbslist/editlistwin.h
+++ b/src/bbslist/editlistwin.h
@@ -26,6 +26,7 @@ namespace BBSLIST
public:
EditListWin( const std::string& url, Glib::RefPtr< Gtk::TreeStore >& treestore );
+ ~EditListWin() noexcept;
void clock_in();
void append_item();
diff --git a/src/bbslist/favoriteview.cpp b/src/bbslist/favoriteview.cpp
index c886e3a4..89f62a89 100644
--- a/src/bbslist/favoriteview.cpp
+++ b/src/bbslist/favoriteview.cpp
@@ -56,12 +56,7 @@ void FavoriteListView::show_view()
{
std::string xml;
- // ファイルが存在しなければ入力を旧ファイル名にする
std::string file_in = CACHE::path_xml_favorite();
- if( CACHE::file_exists( file_in ) != CACHE::EXIST_FILE )
- {
- file_in = CACHE::path_xml_favorite_old();
- }
CACHE::load_rawdata( file_in, xml );
diff --git a/src/bbslist/selectlistview.cpp b/src/bbslist/selectlistview.cpp
index f16c5fc5..1b96acdb 100644
--- a/src/bbslist/selectlistview.cpp
+++ b/src/bbslist/selectlistview.cpp
@@ -20,6 +20,9 @@ SelectListView::SelectListView( const std::string& url, const std::string& arg1,
}
+SelectListView::~SelectListView() noexcept = default;
+
+
void SelectListView::close_view()
{
#ifdef _DEBUG
diff --git a/src/bbslist/selectlistview.h b/src/bbslist/selectlistview.h
index 85c85485..5638b523 100644
--- a/src/bbslist/selectlistview.h
+++ b/src/bbslist/selectlistview.h
@@ -23,7 +23,7 @@ namespace BBSLIST
public:
SelectListView( const std::string& url, const std::string& arg1 = std::string() , const std::string& arg2 = std::string() );
- ~SelectListView() noexcept {}
+ ~SelectListView() noexcept;
SIG_CLOSE_DIALOG sig_close_dialog() { return m_sig_close_dialog; }
SIG_FOCUS_ENTRY_SEARCH sig_focus_entry_search() { return m_sig_focus_entry_search; }
diff --git a/src/bbslist/toolbar.cpp b/src/bbslist/toolbar.cpp
index 95580176..d6c0840e 100644
--- a/src/bbslist/toolbar.cpp
+++ b/src/bbslist/toolbar.cpp
@@ -65,6 +65,9 @@ BBSListToolBar::BBSListToolBar() :
}
+BBSListToolBar::~BBSListToolBar() noexcept = default;
+
+
//
// ボタンのパッキング
//
diff --git a/src/bbslist/toolbar.h b/src/bbslist/toolbar.h
index f2046a02..b27c9f3e 100644
--- a/src/bbslist/toolbar.h
+++ b/src/bbslist/toolbar.h
@@ -28,7 +28,7 @@ namespace BBSLIST
public:
BBSListToolBar();
- ~BBSListToolBar() noexcept {}
+ ~BBSListToolBar() noexcept;
// タブが切り替わった時にDragableNoteBookから呼び出される( Viewの情報を取得する )
void set_view( SKELETON::View * view ) override;
@@ -57,7 +57,7 @@ namespace BBSLIST
public:
EditListToolBar();
- ~EditListToolBar() noexcept {}
+ ~EditListToolBar() noexcept = default;
protected:
diff --git a/src/board/boardadmin.cpp b/src/board/boardadmin.cpp
index 0ae9edb8..f98bc558 100644
--- a/src/board/boardadmin.cpp
+++ b/src/board/boardadmin.cpp
@@ -123,8 +123,7 @@ void BoardAdmin::restore( const bool only_locked )
COMMAND_ARGS command_arg = url_to_openarg( *it_url, true, lock );
// 板がDBに登録されていない場合は表示しない
- if( command_arg.url != URL_ALLLOG && command_arg.arg4 != "SIDEBAR"
- && DBTREE::url_boardbase( command_arg.url ).empty() ){
+ if( command_arg.url.empty() && command_arg.arg4 != "SIDEBAR" ){
MISC::ERRMSG( *it_url + " is not registered" );
list_switchhistory.remove( *it_url );
continue;
@@ -163,7 +162,7 @@ COMMAND_ARGS BoardAdmin::url_to_openarg( const std::string& url, const bool tab,
// 次スレ検索
if( regex.exec( std::string( "(.*)" ) + NEXT_SIGN + ARTICLE_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){
- command_arg.url = regex.str( 1 );
+ command_arg.url = DBTREE::url_boardbase( regex.str( 1 ) );
command_arg.arg4 = "NEXT";
command_arg.arg5 = regex.str( 2 ); // 前スレのアドレス
@@ -180,7 +179,7 @@ COMMAND_ARGS BoardAdmin::url_to_openarg( const std::string& url, const bool tab,
// ログ一覧
else if( regex.exec( std::string( "(.*)" ) + LOG_SIGN, url, offset, icase, newline, usemigemo, wchar )){
- command_arg.url = regex.str( 1 );
+ command_arg.url = DBTREE::url_boardbase( regex.str( 1 ) );
command_arg.arg4 = "LOG";
}
@@ -188,7 +187,7 @@ COMMAND_ARGS BoardAdmin::url_to_openarg( const std::string& url, const bool tab,
// サイドバー
else if( regex.exec( std::string( "(.*)" ) + SIDEBAR_SIGN + "(.*)", url, offset, icase, newline, usemigemo, wchar )){
- command_arg.url = regex.str( 1 );
+ command_arg.url = DBTREE::url_boardbase( regex.str( 1 ) );
command_arg.arg4 = "SIDEBAR";
command_arg.arg5 = regex.str( 2 ); // ディレクトリID
@@ -197,7 +196,7 @@ COMMAND_ARGS BoardAdmin::url_to_openarg( const std::string& url, const bool tab,
// スレビュー
else{
- command_arg.url = url;
+ command_arg.url = DBTREE::url_boardbase( url );
command_arg.arg4 = "MAIN";
}
diff --git a/src/board/boardview.cpp b/src/board/boardview.cpp
index 660734a1..ab5154a8 100644
--- a/src/board/boardview.cpp
+++ b/src/board/boardview.cpp
@@ -62,7 +62,7 @@ void BoardView::save_session()
// 更新した
-bool BoardView::is_updated()
+bool BoardView::is_updated() const
{
const int status = DBTREE::board_status( get_url_board() );
@@ -75,7 +75,7 @@ bool BoardView::is_updated()
// 更新チェックして更新可能か
-bool BoardView::is_check_update()
+bool BoardView::is_check_update() const
{
const int status = DBTREE::board_status( get_url_board() );
diff --git a/src/board/boardview.h b/src/board/boardview.h
index c3790f08..245bffea 100644
--- a/src/board/boardview.h
+++ b/src/board/boardview.h
@@ -20,8 +20,8 @@ namespace BOARD
void save_session() override;
- bool is_updated() override;
- bool is_check_update() override;
+ bool is_updated() const override;
+ bool is_check_update() const override;
void reload() override;
void show_view() override;
diff --git a/src/board/boardviewbase.cpp b/src/board/boardviewbase.cpp
index 625bbfcb..c85e30e1 100644
--- a/src/board/boardviewbase.cpp
+++ b/src/board/boardviewbase.cpp
@@ -125,8 +125,8 @@ BoardViewBase::BoardViewBase( const std::string& url, const bool show_col_board
// 次スレ検索ビューのようにURLの途中に http が入っている場合は取り除く
size_t pos = url.rfind( "http://" );
if( pos == std::string::npos || pos == 0 ) pos = url.rfind( "https://" );
- if( pos != std::string::npos && pos != 0 ) m_url_board = DBTREE::url_subject( url.substr( 0, pos ) );
- else m_url_board = DBTREE::url_subject( url );
+ if( pos != std::string::npos && pos != 0 ) m_url_board = DBTREE::url_boardbase( url.substr( 0, pos ) );
+ else m_url_board = DBTREE::url_boardbase( url );
m_scrwin.add( m_treeview );
m_scrwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS );
@@ -191,7 +191,7 @@ BoardViewBase::BoardViewBase( const std::string& url, const bool show_col_board
}
-BoardViewBase::~BoardViewBase()
+BoardViewBase::~BoardViewBase() noexcept
{
#ifdef _DEBUG
std::cout << "BoardViewBase::~BoardViewBase : " << get_url() << std::endl;
@@ -219,7 +219,7 @@ void BoardViewBase::update_url( const std::string& url_old, const std::string& u
// アイコンのID取得
-int BoardViewBase::get_icon( const std::string& iconname )
+int BoardViewBase::get_icon( const std::string& iconname ) const
{
int id = ICON::NONE;
@@ -240,9 +240,9 @@ int BoardViewBase::get_icon( const std::string& iconname )
//
// コピー用URL(メインウィンドウのURLバーなどに表示する)
//
-std::string BoardViewBase::url_for_copy()
+std::string BoardViewBase::url_for_copy() const
{
- return DBTREE::url_boardbase( get_url_board() );
+ return get_url_board();
}
@@ -680,7 +680,10 @@ void BoardViewBase::update_columns()
Gtk::CellRenderer *cell = column->get_first_cell();
// 実際の描画の際に cellrendere のプロパティをセットするスロット関数
- if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &BoardViewBase::slot_cell_data ) );
+ if( cell ){
+ if( id == COL_SUBJECT ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &BoardViewBase::slot_cell_data_markup ) );
+ else column->set_cell_data_func( *cell, sigc::mem_fun( *this, &BoardViewBase::slot_cell_data ) );
+ }
Gtk::CellRendererText* rentext = dynamic_cast< Gtk::CellRendererText* >( cell );
if( rentext ){
@@ -832,6 +835,33 @@ void BoardViewBase::save_column_width()
+//
+// Subjectの実際の描画の際に cellrendere のプロパティをセットするスロット関数
+//
+void BoardViewBase::slot_cell_data_markup( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it )
+{
+ Gtk::TreeModel::Row row = *it;
+ Gtk::TreePath path = GET_PATH( row );
+
+#ifdef _DEBUG
+// std::cout << "BoardViewBase::slot_cell_data path = " << path.to_string() << std::endl;
+#endif
+
+ // ハイライト色 ( 抽出状態 )
+ if( row[ m_columns.m_col_drawbg ] ){
+ cell->property_cell_background() = CONFIG::get_color( COLOR_BACK_HIGHLIGHT_TREE );
+ cell->property_cell_background_set() = true;
+ }
+
+ else m_treeview.slot_cell_data( cell, it );
+
+ Gtk::CellRendererText* rentext = dynamic_cast< Gtk::CellRendererText* >( cell );
+ rentext->property_text() = "";
+ rentext->property_markup() = row[ m_columns.m_col_subject ];
+}
+
+
+
//
// 実際の描画の際に cellrendere のプロパティをセットするスロット関数
//
@@ -1263,7 +1293,7 @@ void BoardViewBase::redraw_scrollbar()
//
// 色、フォント、表示内容の更新
//
-void BoardViewBase::relayout()
+void BoardViewBase::relayout( const bool completely )
{
m_treeview.init_color( COLOR_CHAR_BOARD, COLOR_BACK_BOARD, COLOR_BACK_BOARD_EVEN );
m_treeview.init_font( CONFIG::get_fontname( FONT_BOARD ) );
@@ -1346,6 +1376,8 @@ void BoardViewBase::update_status()
//
void BoardViewBase::select_item( const std::string& url )
{
+ if( m_url_board != DBTREE::url_boardbase( url ) ) return;
+
const Gtk::TreeModel::Row row = get_row_from_url( url );
if( row ){
Gtk::TreePath path = GET_PATH( row );
@@ -1763,14 +1795,14 @@ Gtk::Menu* BoardViewBase::get_popupmenu( const std::string& url )
//
// 特定の行だけの表示内容更新
//
-// url : subject.txt のアドレス
+// url : boardbase アドレス
// id : DAT の ID(拡張子付き), empty なら全ての行の表示内容を更新する
//
void BoardViewBase::update_item( const std::string& url, const std::string& id )
{
if( is_loading() ) return;
if( ! get_row_size() ) return;
- if( ! get_url_board().empty() && get_url_board() != url ) return;
+ if( get_url_board() != url ) return;
if( id.empty() ){
update_item_all();
@@ -1856,7 +1888,7 @@ void BoardViewBase::update_row_common( const Gtk::TreeModel::Row& row )
const int res = art->get_number();
// タイトル、レス数、抽出
- row[ m_columns.m_col_subject ] = art->get_subject();
+ row[ m_columns.m_col_subject ] = MISC::to_markup( art->get_modified_subject( true ) );
row[ m_columns.m_col_res ] = res;
// 読み込み数
@@ -1880,6 +1912,10 @@ void BoardViewBase::update_row_common( const Gtk::TreeModel::Row& row )
row[ m_columns.m_col_new ] = -1;
}
+ // 速度
+ if( ( art->get_status() & STATUS_NORMAL ) && ! art->is_924() )
+ row[ m_columns.m_col_speed ] = art->get_speed();
+
//
// マーク
@@ -2145,7 +2181,7 @@ bool BoardViewBase::slot_motion_notify( GdkEventMotion* event )
m_treeview.set_tooltip_min_width( column->get_width() );
if( column->get_title() == ITEM_NAME_BOARD ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_board ) );
- else if( column->get_title() == ITEM_NAME_NAME ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_subject ) );
+ else if( column->get_title() == ITEM_NAME_NAME ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_subject ), true );
else if( column->get_title() == ITEM_NAME_SINCE ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_since ) );
else if( column->get_title() == ITEM_NAME_LASTWRITE ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_write ) );
else if( column->get_title() == ITEM_NAME_ACCESS ) m_treeview.set_str_tooltip( get_name_of_cell( path, m_columns.m_col_access ) );
@@ -2387,7 +2423,7 @@ void BoardViewBase::slot_copy_title_url()
if( m_path_selected.empty() ) return;
const std::string url = DBTREE::url_readcgi( path2daturl( m_path_selected ), 0, 0 );
- const std::string name = DBTREE::article_subject( url );
+ const std::string name = MISC::to_plain( DBTREE::article_subject( url ) );
MISC::CopyClipboard( name + '\n' + url );
}
@@ -2552,7 +2588,7 @@ std::string BoardViewBase::path2url_board( const Gtk::TreePath& path )
{
if( ! get_url_board().empty() ) return get_url_board();
if( path.empty() ) return std::string();
- return DBTREE::url_subject( path2daturl( path ) );
+ return DBTREE::url_boardbase( path2daturl( path ) );
}
@@ -2576,15 +2612,17 @@ bool BoardViewBase::drawout( const bool force_reset )
unsorted_column();
JDLIB::Regex regex;
+ JDLIB::RegexPattern regexptn;
const bool icase = true; // 大文字小文字区別しない
const bool newline = true; // . に改行をマッチさせない
const bool usemigemo = true; // migemo使用
- const bool wchar = true; // 全角半角の区別をしない
+ const bool wchar = false; // 全角半角の区別をしない
+ const bool norm = true; // Unicodeの互換文字を区別しない
Gtk::TreeModel::Children child = m_liststore->children();
Gtk::TreeModel::Children::iterator it = child.begin();
- if ( ! reset ) regex.compile( query, icase, newline, usemigemo, wchar );
+ if ( ! reset ) regexptn.set( query, icase, newline, usemigemo, wchar, norm );
for( ; it != child.end() ; ++it ){
@@ -2592,7 +2630,7 @@ bool BoardViewBase::drawout( const bool force_reset )
const Glib::ustring subject = row[ m_columns.m_col_subject ];
if( reset ) row[ m_columns.m_col_drawbg ] = false;
- else if( regex.exec( subject, 0 ) ){
+ else if( regex.match( regexptn, MISC::to_plain( subject ), 0 ) ){
row[ m_columns.m_col_drawbg ] = true;
++hit;
@@ -2664,7 +2702,8 @@ void BoardViewBase::exec_search()
const bool icase = true; // 大文字小文字区別しない
const bool newline = true; // . に改行をマッチさせない
const bool usemigemo = true; // migemo使用
- const bool wchar = true; // 全角半角の区別をしない
+ const bool wchar = false; // 全角半角の区別をしない
+ const bool norm = true; // Unicodeの互換文字を区別しない
#ifdef _DEBUG
std::cout << "BoardViewBase::search start = " << path_start.to_string() << " query = " << query << std::endl;
@@ -2690,7 +2729,7 @@ void BoardViewBase::exec_search()
if( path == path_start ) break;
Glib::ustring subject = get_name_of_cell( path, m_columns.m_col_subject );
- if( regex.exec( query, subject, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.exec( query, MISC::to_plain( subject ), offset, icase, newline, usemigemo, wchar, norm ) ){
m_treeview.scroll_to_row( path, 0 );
m_treeview.set_cursor( path );
return;
@@ -2931,7 +2970,7 @@ void BoardViewBase::slot_search_next()
if( m_path_selected.empty() ) return;
const std::string url = path2daturl( m_path_selected );
- CORE::core_set_command( "open_board_next", DBTREE::url_subject( url ) , url );
+ CORE::core_set_command( "open_board_next", DBTREE::url_boardbase( url ) , url );
}
@@ -2955,10 +2994,11 @@ void BoardViewBase::slot_abone_thread()
// あぼーん情報更新
std::list< std::string > words = DBTREE::get_abone_list_word_thread( get_url_board() );
std::list< std::string > regexs = DBTREE::get_abone_list_regex_thread( get_url_board() );
- const int number = DBTREE::get_abone_number_thread( get_url_board() );
+ const int min_number = DBTREE::get_abone_min_number_thread( get_url_board() );
+ const int max_number = DBTREE::get_abone_max_number_thread( get_url_board() );
const int hour = DBTREE::get_abone_hour_thread( get_url_board() );
const bool redraw = false; // 板の再描画はしない
- DBTREE::reset_abone_thread( get_url_board(), threads, words, regexs, number, hour, redraw );
+ DBTREE::reset_abone_thread( get_url_board(), threads, words, regexs, min_number, max_number, hour, redraw );
m_treeview.delete_selected_rows( true );
}
@@ -3001,7 +3041,7 @@ void BoardViewBase::set_article_to_buffer()
info.type = TYPE_THREAD;
info.parent = BOARD::get_admin()->get_win();
info.url = art->get_url();
- info.name = name.raw();
+ info.name = MISC::to_plain( name.raw() );
info.path = path.to_string();
list_info.push_back( info );
diff --git a/src/board/boardviewbase.h b/src/board/boardviewbase.h
index daa03951..bf375aaf 100644
--- a/src/board/boardviewbase.h
+++ b/src/board/boardviewbase.h
@@ -101,10 +101,10 @@ namespace BOARD
public:
BoardViewBase( const std::string& url, const bool show_col_board );
- ~BoardViewBase();
+ ~BoardViewBase() noexcept;
const std::string& get_url_board() const { return m_url_board; }
- std::string url_for_copy() override;
+ std::string url_for_copy() const override;
// 行数
int get_row_size();
@@ -115,7 +115,7 @@ namespace BOARD
void update_url( const std::string& url_old, const std::string& url_new ) override;
- int get_icon( const std::string& iconname ) override;
+ int get_icon( const std::string& iconname ) const override;
bool is_loading() const override { return m_loading; }
bool set_command( const std::string& command,
const std::string& arg1 = {},
@@ -130,7 +130,7 @@ namespace BOARD
void stop() override;
void show_view() override;
void redraw_scrollbar() override;
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void focus_view() override;
void focus_out() override;
void close_view() override;
@@ -231,6 +231,7 @@ namespace BOARD
// 列の幅の保存
virtual void save_column_width();
+ void slot_cell_data_markup( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it );
void slot_cell_data( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& it );
// 全ての行の表示内容更新
diff --git a/src/board/boardviewnext.cpp b/src/board/boardviewnext.cpp
index cced5f86..75e9061a 100644
--- a/src/board/boardviewnext.cpp
+++ b/src/board/boardviewnext.cpp
@@ -12,6 +12,7 @@
#include "skeleton/msgdiag.h"
#include "jdlib/tfidf.h"
+#include "jdlib/miscutil.h"
#include "config/globalconf.h"
@@ -180,7 +181,7 @@ void BoardViewNext::slot_abone_thread()
//
void BoardViewNext::update_boardname()
{
- const std::string title = "[ 次スレ検索 ] - " + DBTREE::article_subject( m_url_pre_article );
+ const std::string title = "[ 次スレ検索 ] - " + MISC::to_plain( DBTREE::article_modified_subject( m_url_pre_article ) );
// ウィンドウタイトル表示
set_title( title );
diff --git a/src/board/columns.h b/src/board/columns.h
index 89d444d0..cea1af9a 100644
--- a/src/board/columns.h
+++ b/src/board/columns.h
@@ -66,7 +66,7 @@ namespace BOARD
add( m_col_article );
}
- ~TreeColumns(){}
+ ~TreeColumns() noexcept = default;
};
}
diff --git a/src/board/preference.cpp b/src/board/preference.cpp
index 1a39fcdb..c77e8eb0 100644
--- a/src/board/preference.cpp
+++ b/src/board/preference.cpp
@@ -10,8 +10,9 @@
#include "skeleton/msgdiag.h"
-#include "jdlib/miscutil.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/misctime.h"
+#include "jdlib/miscutil.h"
#include "config/globalconf.h"
@@ -110,10 +111,10 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
str_cookies = "クッキー:\n";
std::list< std::string >::iterator it = list_cookies.begin();
for( ; it != list_cookies.end(); ++it )
- str_cookies += MISC::Iconv( (*it), DBTREE::board_charset( get_url() ), "UTF-8" ) + "\n";
+ str_cookies += MISC::Iconv( (*it), DBTREE::board_charcode( get_url() ), CHARCODE_UTF8 ) + "\n";
}
- const std::string keyword = DBTREE::board_keyword_for_write( get_url() );
+ const std::string& keyword = DBTREE::board_keyword_for_write( get_url() );
if( ! keyword.empty() ) str_cookies += "\nキーワード: " + keyword + "\n";
m_edit_cookies.set_text( str_cookies );
@@ -147,10 +148,31 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
m_hbox_live.set_spacing( 4 );
m_hbox_live.pack_start( m_label_live, Gtk::PACK_SHRINK );
m_hbox_live.pack_start( m_spin_live, Gtk::PACK_SHRINK );
- m_hbox_live.pack_start( m_check_live, Gtk::PACK_SHRINK );
+ m_hbox_live.pack_start( m_check_live );
set_activate_entry( m_spin_live );
+ // 文字エンコーディング
+ m_label_charset.set_text( "エンコーディング:" );
+#if GTKMM_CHECK_VERSION(2,24,0)
+ m_combo_charset.append( MISC::charcode_to_cstr( CHARCODE_UTF8 ) );
+ m_combo_charset.append( MISC::charcode_to_cstr( CHARCODE_SJIS ) );
+ m_combo_charset.append( MISC::charcode_to_cstr( CHARCODE_EUCJP ) );
+ m_combo_charset.set_active_text( MISC::charcode_to_cstr( DBTREE::board_charcode( get_url() ) ) );
+#else
+ std::list< Glib::ustring > list_charset;
+ list_charset.push_back( MISC::charcode_to_cstr( CHARCODE_UTF8 ) );
+ list_charset.push_back( MISC::charcode_to_cstr( CHARCODE_SJIS ) );
+ list_charset.push_back( MISC::charcode_to_cstr( CHARCODE_EUCJP ) );
+ m_combo_charset.set_popdown_strings( list_charset );
+ m_combo_charset.get_entry()->set_text( MISC::charcode_to_cstr( DBTREE::board_charcode( get_url() ) ) );
+ m_combo_charset.get_entry()->set_editable( false );
+ m_combo_charset.set_value_in_list( false );
+#endif
+
+ m_hbox_live.pack_start( m_label_charset, Gtk::PACK_SHRINK );
+ m_hbox_live.pack_start( m_combo_charset, Gtk::PACK_SHRINK );
+
// 一般ページのパッキング
m_label_max_line.set_text( MISC::itostr( DBTREE::line_number( get_url() ) * 2 ) );
m_label_max_byte.set_text( MISC::itostr( DBTREE::message_count( get_url() ) ) );
@@ -289,16 +311,27 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
// スレ数、時間
m_label_abone_thread.set_text( "以下の数字が0の時は、設定メニューの全体あぼ〜ん設定で指定した数字が用いられます。\nまたキャッシュにログがあるスレはあぼ〜んされません。\n\n" );
- m_label_number.set_text( "レス以上のスレをあぼ〜ん" );
- m_spin_number.set_range( 0, 9999 );
- m_spin_number.set_increments( 1, 1 );
- m_spin_number.set_value( DBTREE::get_abone_number_thread( get_url() ) );
-
- m_hbox_number.set_spacing( 4 );
- m_hbox_number.pack_start( m_spin_number, Gtk::PACK_SHRINK );
- m_hbox_number.pack_start( m_label_number, Gtk::PACK_SHRINK );
+ m_label_min_number.set_text( "レス以下のスレをあぼ〜ん" );
+ m_spin_min_number.set_range( 0, CONFIG::get_max_resnumber() );
+ m_spin_min_number.set_increments( 1, 1 );
+ m_spin_min_number.set_value( DBTREE::get_abone_min_number_thread( get_url() ) );
- set_activate_entry( m_spin_number );
+ m_hbox_min_number.set_spacing( 4 );
+ m_hbox_min_number.pack_start( m_spin_min_number, Gtk::PACK_SHRINK );
+ m_hbox_min_number.pack_start( m_label_min_number, Gtk::PACK_SHRINK );
+
+ set_activate_entry( m_spin_max_number );
+
+ m_label_max_number.set_text( "レス以上のスレをあぼ〜ん" );
+ m_spin_max_number.set_range( 0, CONFIG::get_max_resnumber() );
+ m_spin_max_number.set_increments( 1, 1 );
+ m_spin_max_number.set_value( DBTREE::get_abone_max_number_thread( get_url() ) );
+
+ m_hbox_max_number.set_spacing( 4 );
+ m_hbox_max_number.pack_start( m_spin_max_number, Gtk::PACK_SHRINK );
+ m_hbox_max_number.pack_start( m_label_max_number, Gtk::PACK_SHRINK );
+
+ set_activate_entry( m_spin_max_number );
m_label_hour.set_text( "時間以上スレ立てから経過したスレをあぼ〜ん" );
m_spin_hour.set_range( 0, 9999 );
@@ -314,7 +347,8 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url, const std
m_vbox_abone_thread.set_border_width( 16 );
m_vbox_abone_thread.set_spacing( 8 );
m_vbox_abone_thread.pack_start( m_label_abone_thread, Gtk::PACK_SHRINK );
- m_vbox_abone_thread.pack_start( m_hbox_number, Gtk::PACK_SHRINK );
+ m_vbox_abone_thread.pack_start( m_hbox_min_number, Gtk::PACK_SHRINK );
+ m_vbox_abone_thread.pack_start( m_hbox_max_number, Gtk::PACK_SHRINK );
m_vbox_abone_thread.pack_start( m_hbox_hour, Gtk::PACK_SHRINK );
// スレあぼーん
@@ -403,7 +437,7 @@ void Preferences::slot_clear_post_history()
DBTREE::board_clear_all_post_history( get_url() );
// スレ一覧とスレビューの表示更新
- CORE::core_set_command( "update_board", DBTREE::url_subject( get_url() ) );
+ CORE::core_set_command( "update_board", DBTREE::url_boardbase( get_url() ) );
CORE::core_set_command( "redraw_article" );
}
@@ -499,6 +533,14 @@ void Preferences::slot_ok_clicked()
else if( tmpmail.empty() ) tmpmail = JD_MAIL_BLANK; // 空白の場合 JD_MAIL_BLANK をセットする
DBTREE::board_set_write_mail( get_url(), tmpmail );
+ // charset
+#if GTKMM_CHECK_VERSION(2,24,0)
+ std::string tmpcharset = m_combo_charset.get_active_text();
+#else
+ std::string tmpcharset = m_combo_charset.get_entry()->get_text();
+#endif
+ DBTREE::board_set_charcode( get_url(), MISC::charcode_from_cstr( tmpcharset.c_str() ) );
+
// 実況間隔
int live_sec = 0;
if( m_check_live.get_active() ) live_sec = m_spin_live.get_value_as_int();
@@ -523,11 +565,12 @@ void Preferences::slot_ok_clicked()
std::list< std::string > list_thread = MISC::get_lines( m_edit_thread.get_text() );
std::list< std::string > list_word_thread = MISC::get_lines( m_edit_word_thread.get_text() );
std::list< std::string > list_regex_thread = MISC::get_lines( m_edit_regex_thread.get_text() );
- const int number = m_spin_number.get_value_as_int();
+ const int min_number = m_spin_min_number.get_value_as_int();
+ const int max_number = m_spin_max_number.get_value_as_int();
const int hour = m_spin_hour.get_value_as_int();
const bool redraw = true; // ここでスレ一覧の再描画指定をする
- DBTREE::reset_abone_thread( get_url(), list_thread, list_word_thread, list_regex_thread, number, hour, redraw );
+ DBTREE::reset_abone_thread( get_url(), list_thread, list_word_thread, list_regex_thread, min_number, max_number, hour, redraw );
DBTREE::board_save_info( get_url() );
}
diff --git a/src/board/preference.h b/src/board/preference.h
index 7b86abce..539b97b7 100644
--- a/src/board/preference.h
+++ b/src/board/preference.h
@@ -83,6 +83,14 @@ namespace BOARD
Gtk::CheckButton m_check_live;
SKELETON::SpinButton m_spin_live;
+ // 文字エンコーディング
+ Gtk::Label m_label_charset;
+#if GTKMM_CHECK_VERSION(2,24,0)
+ Gtk::ComboBoxText m_combo_charset;
+#else
+ Gtk::Combo m_combo_charset;
+#endif
+
// プロキシ
Gtk::VBox m_vbox_proxy;
Gtk::Label m_label_proxy;
@@ -130,9 +138,13 @@ namespace BOARD
Gtk::VBox m_vbox_abone_thread;
Gtk::Label m_label_abone_thread;
- Gtk::HBox m_hbox_number;
- Gtk::Label m_label_number;
- SKELETON::SpinButton m_spin_number;
+ Gtk::HBox m_hbox_min_number;
+ Gtk::Label m_label_min_number;
+ SKELETON::SpinButton m_spin_min_number;
+
+ Gtk::HBox m_hbox_max_number;
+ Gtk::Label m_label_max_number;
+ SKELETON::SpinButton m_spin_max_number;
Gtk::HBox m_hbox_hour;
Gtk::Label m_label_hour;
diff --git a/src/board/toolbar.cpp b/src/board/toolbar.cpp
index 88a5bb63..4c5c87bb 100644
--- a/src/board/toolbar.cpp
+++ b/src/board/toolbar.cpp
@@ -26,6 +26,10 @@ BoardToolBar::BoardToolBar() :
add_search_control_mode( CONTROL::MODE_BOARD );
}
+
+BoardToolBar::~BoardToolBar() noexcept = default;
+
+
// ボタンのパッキング
// virtual
void BoardToolBar::pack_buttons()
diff --git a/src/board/toolbar.h b/src/board/toolbar.h
index 3f8c16cc..d4a13acb 100644
--- a/src/board/toolbar.h
+++ b/src/board/toolbar.h
@@ -16,7 +16,7 @@ namespace BOARD
public:
BoardToolBar();
- ~BoardToolBar() noexcept {}
+ ~BoardToolBar() noexcept;
// ツールバー表示切り替え時に検索関係の wiget の位置を変更する
void unpack_pack();
diff --git a/src/boarditemmenupref.h b/src/boarditemmenupref.h
index f5669513..a4080743 100644
--- a/src/boarditemmenupref.h
+++ b/src/boarditemmenupref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
BoardItemMenuPref( Gtk::Window* parent, const std::string& url );
- ~BoardItemMenuPref() noexcept {}
+ ~BoardItemMenuPref() noexcept = default;
private:
diff --git a/src/boarditempref.h b/src/boarditempref.h
index e215c9d4..082c4b65 100644
--- a/src/boarditempref.h
+++ b/src/boarditempref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
BoardItemColumnPref( Gtk::Window* parent, const std::string& url );
- ~BoardItemColumnPref() noexcept {}
+ ~BoardItemColumnPref() noexcept = default;
private:
@@ -30,7 +30,7 @@ namespace CORE
public:
BoardItemPref( Gtk::Window* parent, const std::string& url );
- ~BoardItemPref() noexcept {}
+ ~BoardItemPref() noexcept = default;
private:
diff --git a/src/cache.cpp b/src/cache.cpp
index 4df85845..8ed72765 100644
--- a/src/cache.cpp
+++ b/src/cache.cpp
@@ -51,15 +51,6 @@ std::string CACHE::path_conf_bkup()
}
-// 旧設定ファイル
-std::string CACHE::path_conf_old()
-{
- std::string home = MISC::getenv_limited( ENV_HOME, MAX_SAFE_PATH );
-
- return home + "/.jdrc";
-}
-
-
// セッション情報ファイル
std::string CACHE::path_session()
{
@@ -104,7 +95,7 @@ std::string CACHE::path_root()
}
-// 板リスト
+// 板リスト ( 1.9.5-beta070611以前は "list_main.xml" )
std::string CACHE::path_xml_listmain()
{
return CACHE::path_root() + "boards.xml";
@@ -114,14 +105,9 @@ std::string CACHE::path_xml_listmain_bkup()
{
return CACHE::path_xml_listmain() + ".bkup";
}
-// 1.9.5-beta070611以前
-std::string CACHE::path_xml_listmain_old()
-{
- return CACHE::path_root() + "list_main.xml";
-}
-// お気に入り
+// お気に入り ( 1.9.5-beta070611以前は "favorite.xml" )
std::string CACHE::path_xml_favorite()
{
return CACHE::path_root() + "bookmark.xml";
@@ -131,11 +117,6 @@ std::string CACHE::path_xml_favorite_bkup()
{
return CACHE::path_xml_favorite() + ".bkup";
}
-// 1.9.5-beta070611以前
-std::string CACHE::path_xml_favorite_old()
-{
- return CACHE::path_root() + "favorite.xml";
-}
// 外部板設定ファイル( navi2ch 互換 )
@@ -151,11 +132,6 @@ std::string CACHE::path_usrcmd()
return CACHE::path_root() + "usrcmd.xml";
}
-std::string CACHE::path_usrcmd_old()
-{
- return CACHE::path_root() + "usrcmd.txt";
-}
-
// リンクフィルタ設定ファイル
std::string CACHE::path_linkfilter()
@@ -164,6 +140,13 @@ std::string CACHE::path_linkfilter()
}
+// 文字列置換設定ファイル
+std::string CACHE::path_replacestr()
+{
+ return CACHE::path_root() + "replacestr.xml";
+}
+
+
// URL変換設定ファイル
std::string CACHE::path_urlreplace()
{
diff --git a/src/cache.h b/src/cache.h
index a7c0ac5b..e0b130bf 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -44,7 +44,6 @@ namespace CACHE
// 設定ファイル
std::string path_conf();
std::string path_conf_bkup();
- std::string path_conf_old(); // 旧ファイル
// セッション情報ファイル
std::string path_session();
@@ -61,23 +60,23 @@ namespace CACHE
// 板
std::string path_xml_listmain();
std::string path_xml_listmain_bkup();
- std::string path_xml_listmain_old();
// お気に入り
std::string path_xml_favorite();
std::string path_xml_favorite_bkup();
- std::string path_xml_favorite_old();
// 外部板設定ファイル( navi2ch 互換 )
std::string path_etcboard();
// ユーザーコマンド設定ファイル
std::string path_usrcmd();
- std::string path_usrcmd_old();
// リンクフィルタ
std::string path_linkfilter();
+ // 文字列置換
+ std::string path_replacestr();
+
// URL変換設定ファイル
std::string path_urlreplace();
diff --git a/src/charcode.h b/src/charcode.h
new file mode 100644
index 00000000..05553c0a
--- /dev/null
+++ b/src/charcode.h
@@ -0,0 +1,16 @@
+// キャラクタコード
+
+#ifndef _CHAR_CODE_H
+#define _CHAR_CODE_H
+
+enum CharCode
+{
+ CHARCODE_UNKNOWN = 0,
+ CHARCODE_ASCII,
+ CHARCODE_EUCJP,
+ CHARCODE_JIS,
+ CHARCODE_SJIS,
+ CHARCODE_UTF8
+};
+
+#endif
diff --git a/src/config/aboutconfig.cpp b/src/config/aboutconfig.cpp
index 3b81786a..c61581b7 100644
--- a/src/config/aboutconfig.cpp
+++ b/src/config/aboutconfig.cpp
@@ -49,6 +49,7 @@ void AboutConfig::pack_widgets()
m_label.set_text( "動作保証外です。高度な設定を変更するとJDimが誤作動する場合があります。" );
m_liststore = Gtk::ListStore::create( m_columns );
+ m_treeview.property_fixed_height_mode() = true;
m_treeview.set_model( m_liststore );
m_treeview.set_size_request( 700, 400 );
m_treeview.signal_row_activated().connect( sigc::mem_fun( *this, &AboutConfig::slot_row_activated ) );
@@ -62,6 +63,8 @@ void AboutConfig::pack_widgets()
if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &AboutConfig::slot_cell_data ) );
column = Gtk::manage( new Gtk::TreeViewColumn( "値", m_columns.m_col_value ) );
+ column->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED );
+ column->set_resizable( true );
m_treeview.append_column( *column );
cell = column->get_first_cell();
if( cell ) column->set_cell_data_func( *cell, sigc::mem_fun( *this, &AboutConfig::slot_cell_data ) );
@@ -126,9 +129,14 @@ void AboutConfig::append_rows()
append_row( "2chログイン認証サーバのアドレス", get_confitem()->url_login2ch, CONF_LOGIN2CH );
append_row( "p2ログイン認証サーバのアドレス", get_confitem()->url_loginp2, CONF_LOGINP2 );
append_row( "BE認証サーバのアドレス", get_confitem()->url_loginbe, CONF_LOGINBE );
- append_row( "2chにアクセスするときのエージェント名", get_confitem()->agent_for2ch, CONF_AGENT_FOR2CH );
- append_row( "2ch以外のサーバにアクセスするときのエージェント名", get_confitem()->agent_for_data, CONF_AGENT_FOR_DATA );
- append_row( "2chログイン認証サーバにアクセスするときのエージェント名", get_confitem()->x_2ch_ua, CONF_X_2CH_UA );
+ append_row( "5chにアクセスするときのエージェント名", get_confitem()->agent_for2ch, CONF_AGENT_FOR2CH );
+ append_row( "5ch以外のサーバにアクセスするときのエージェント名", get_confitem()->agent_for_data, CONF_AGENT_FOR_DATA );
+ append_row( "5chログイン認証サーバにアクセスするときのエージェント名", get_confitem()->x_2ch_ua, CONF_X_2CH_UA );
+ append_row( "TLSでノンブロッキングI/Oを使用する", get_confitem()->tls_nonblocking, CONF_TLS_NONBLOCKING );
+ append_row( "TLSでサーバの証明書をチェックする", get_confitem()->verify_cert, CONF_VERIFY_CERT );
+#ifndef USE_NSS
+ append_row( "信頼するルート証明書のPATH", get_confitem()->root_cafile, CONF_ROOT_CAFILE );
+#endif
append_row( "スレの読み込み時のタイムアウト値(秒)", get_confitem()->loader_timeout, CONF_LOADER_TIMEOUT );
append_row( "書き込み時のタイムアウト値(秒)", get_confitem()->loader_timeout_post, CONF_LOADER_TIMEOUT_POST );
append_row( "画像等のデータのロード時のタイムアウト値(秒)", get_confitem()->loader_timeout_img, CONF_LOADER_TIMEOUT_IMG );
@@ -136,10 +144,11 @@ void AboutConfig::append_rows()
append_row( "一般データのダウンロード時のバッファサイズ(Kbyte)", get_confitem()->loader_bufsize, CONF_LOADER_BUFSIZE );
append_row( "スレ一覧のダウンロード時のバッファサイズ(Kbyte)", get_confitem()->loader_bufsize_board, CONF_LOADER_BUFSIZE_BOARD );
append_row( "同一ホストに対する最大コネクション数( 1 または 2 )", get_confitem()->connection_num, CONF_CONNECTION_NUM );
- append_row( "2chのクッキー:HAPを保存する", get_confitem()->use_cookie_hap, CONF_USE_COOKIE_HAP );
- append_row( "2chのクッキー:HAP", get_confitem()->cookie_hap, CONF_COOKIE_HAP );
+ append_row( "5chのクッキー:HAPを保存する", get_confitem()->use_cookie_hap, CONF_USE_COOKIE_HAP );
+ append_row( "5chのクッキー:HAP", get_confitem()->cookie_hap, CONF_COOKIE_HAP );
append_row( "BBSPINKのクッキー:HAP", get_confitem()->cookie_hap_bbspink, CONF_COOKIE_HAP_BBSPINK );
- append_row( "2chの過去ログ取得時にofflaw2を使用する", get_confitem()->use_offlaw2_2ch, CONF_USE_OFFLAW2_2CH );
+ append_row( "5chの過去ログを外部のサイトから取得する", get_confitem()->use_external_log, CONF_USE_EXTERNAL_LOG );
+ append_row( "5chの過去ログを取得するサイトのURL", get_confitem()->url_external_log, CONF_URL_EXTERNAL_LOG );
// ツリービュー
append_row( "" );
@@ -207,6 +216,7 @@ void AboutConfig::append_rows()
append_row( "レスを引用コピーするときに前に付ける引用文字", get_confitem()->ref_prefix, CONF_REF_PREFIX );
append_row( "引用文字の後のスペース数", get_confitem()->ref_prefix_space, CONF_REF_PREFIX_SPACE );
append_row( "RFC規定外の文字(^など)もURL判定に用いる", get_confitem()->loose_url, CONF_LOOSE_URL );
+ append_row( "URLのパーセントコードをデコードして表示する", get_confitem()->percent_decode, CONF_PERCENT_DECODE );
append_row( "再読み込みボタンを押したときに全タブを更新する", get_confitem()->reload_allthreads, CONF_RELOAD_ALLTHREAD );
append_row( "発言(同一ID)数をカウントする", get_confitem()->check_id, CONF_CHECK_ID );
append_row( "レス参照数で色を変える回数(高)", get_confitem()->num_reference_high, CONF_NUM_REFERENCE_HIGH );
@@ -265,6 +275,7 @@ void AboutConfig::append_rows()
append_row( "スレビューのスクロールバーを左に配置する", get_confitem()->left_scrbar, CONF_LEFT_SCRBAR );
append_row( "メニューバーを非表示にした時にダイアログを表示", get_confitem()->show_hide_menubar_diag, CONF_SHOW_HIDE_MENUBAR_DIAG );
append_row( "状態変更時にメインステータスバーの色を変える", get_confitem()->change_stastatus_color, CONF_CHANGE_STASTATUS_COLOR );
+ append_row( "状態変更時にスレビュータイトルの色を変える", get_confitem()->change_statitle_color, CONF_CHANGE_STATITLE_COLOR );
// 次スレ検索
append_row( "" );
@@ -296,6 +307,8 @@ void AboutConfig::append_rows()
#endif
append_row( "FIFOの作成などにエラーがあったらダイアログを表示する", get_confitem()->show_diag_fifo_error, CONF_SHOW_DIAG_FIFO_ERROR );
append_row( "指定した分ごとにセッションを自動保存 (0: 保存しない)", get_confitem()->save_session, CONF_SAVE_SESSION );
+ append_row( "不正なMS932文字列をUTF-8と見なす", get_confitem()->broken_sjis_be_utf8, CONF_BROKEN_SJIS_BE_UTF8 );
+ append_row( "不正な数値文字参照を無理矢理変換する", get_confitem()->correct_character_reference, CONF_CORRECT_CHAR_REFERENCE );
}
diff --git a/src/config/aboutconfig.h b/src/config/aboutconfig.h
index 4988eab2..33102ad5 100644
--- a/src/config/aboutconfig.h
+++ b/src/config/aboutconfig.h
@@ -60,7 +60,7 @@ namespace CONFIG
public:
AboutConfig( Gtk::Window* parent );
- ~AboutConfig() noexcept {}
+ ~AboutConfig() noexcept = default;
private:
diff --git a/src/config/configitems.cpp b/src/config/configitems.cpp
index 59e7d012..95ed4329 100644
--- a/src/config/configitems.cpp
+++ b/src/config/configitems.cpp
@@ -9,6 +9,7 @@
#include "configitems.h"
#include "defaultconf.h"
+#include "globalconf.h"
#include "jdlib/confloader.h"
#include "jdlib/miscutil.h"
@@ -66,8 +67,8 @@ ConfigItems::ConfigItems()
fontname.resize( FONT_NUM );
}
-ConfigItems::~ConfigItems() noexcept
-{}
+ConfigItems::~ConfigItems() noexcept = default;
+
// 設定読み込み
bool ConfigItems::load( const bool restore )
@@ -75,22 +76,8 @@ bool ConfigItems::load( const bool restore )
std::string path_conf;
// restoreモード
- if( restore )
- {
- path_conf = CACHE::path_conf_bkup();
- }
- else
- {
- path_conf = CACHE::path_conf();
-
- // 新設定ファイルが無く、かつキャッシュディレクトリが存在していたら旧ファイルから設定を引き継ぐ
- if( CACHE::file_exists( path_conf ) != CACHE::EXIST_FILE
- && CACHE::file_exists( CACHE::path_root() ) == CACHE::EXIST_DIR
- && CACHE::file_exists( CACHE::path_conf_old() ) == CACHE::EXIST_FILE ){
-
- path_conf = CACHE::path_conf_old();
- }
- }
+ if( restore ) path_conf = CACHE::path_conf_bkup();
+ else path_conf = CACHE::path_conf();
JDLIB::ConfLoader cf( path_conf, std::string() );
@@ -169,6 +156,15 @@ bool ConfigItems::load( const bool restore )
// ipv6使用
use_ipv6 = cf.get_option_bool( "use_ipv6", CONF_USE_IPV6 );
+ // TLSでノンブロッキングI/Oを使用する
+ tls_nonblocking = cf.get_option_bool( "tls_nonblocking", CONF_TLS_NONBLOCKING );
+
+ // TLSでサーバの証明書をチェックする
+ verify_cert = cf.get_option_bool( "verify_cert", CONF_VERIFY_CERT );
+
+ // 信頼するルート証明書
+ root_cafile = cf.get_option_str( "root_cafile", CONF_ROOT_CAFILE );
+
// 同一ホストに対する最大コネクション数( 1 または 2 )
connection_num = cf.get_option_int( "connection_num", CONF_CONNECTION_NUM, 1, 2 );
@@ -179,8 +175,9 @@ bool ConfigItems::load( const bool restore )
cookie_hap = cf.get_option_str( "cookie_hap", CONF_COOKIE_HAP );
cookie_hap_bbspink = cf.get_option_str( "cookie_hap_bbspink", CONF_COOKIE_HAP_BBSPINK );
- // 2chの過去ログ取得時にofflaw2を使用する
- use_offlaw2_2ch = cf.get_option_bool( "use_offlaw2_2ch", CONF_USE_OFFLAW2_2CH );
+ // 2chの過去ログを外部のサイトから取得する
+ use_external_log = cf.get_option_bool( "use_external_log", CONF_USE_EXTERNAL_LOG );
+ url_external_log = cf.get_option_str( "url_external_log", CONF_URL_EXTERNAL_LOG );
// ブラウザ設定ダイアログのコンボボックスの番号
browsercombo_id = cf.get_option_int( "browsercombo_id", CONF_BROWSER_NO, 0, CORE::get_browser_number() -1 );
@@ -280,10 +277,6 @@ bool ConfigItems::load( const bool restore )
menu_search_title = cf.get_option_str( "menu_search_title", CONF_MENU_SEARCH_TITLE );
url_search_title = cf.get_option_str( "url_search_title", CONF_URL_SEARCH_TITLE );
- // p2 書き込み用アドレス
- url_writep2 = cf.get_option_str( "url_writep2", CONF_URL_WRITEP2 );
- url_resp2 = cf.get_option_str( "url_resp2", CONF_URL_RESP2 );
-
// スレタイ検索用正規表現
regex_search_title = cf.get_option_str( "regex_search_title", CONF_REGEX_SEARCH_TITLE );
@@ -300,6 +293,9 @@ bool ConfigItems::load( const bool restore )
// スレビューの選択色でgtkrcの設定を使用するか
use_select_gtkrc = cf.get_option_bool( "use_select_gtkrc", CONF_USE_SELECT_GTKRC );
+ // スレビューでHTMLタグ指定の色を使用するか
+ use_color_html = cf.get_option_bool( "use_color_html", CONF_USE_COLOR_HTML );
+
// ツリービューの行間スペース
tree_ypad = cf.get_option_int( "tree_ypad", CONF_TREE_YPAD, 0, 64 );
@@ -476,6 +472,9 @@ bool ConfigItems::load( const bool restore )
// datのパース時にURL判定を甘くする(^なども含める)
loose_url = cf.get_option_bool( "loose_url", CONF_LOOSE_URL );
+ // URLのパーセントコードをデコードして表示する
+ percent_decode = cf.get_option_bool( "percent_decode", CONF_PERCENT_DECODE );
+
// ユーザーコマンドで選択できない項目を非表示にする
hide_usrcmd = cf.get_option_bool( "hide_usrcmd", CONF_HIDE_USRCMD );
@@ -524,7 +523,8 @@ bool ConfigItems::load( const bool restore )
remove_old_abone_thread = cf.get_option_int( "remove_old_abone_thread", CONF_REMOVE_OLD_ABONE_THREAD, 0, 2 );
// スレ あぼーん( レス数 )
- abone_number_thread = cf.get_option_int( "abone_number_thread", CONF_ABONE_NUMBER_THREAD, 0, 9999 );
+ abone_min_number_thread = cf.get_option_int( "abone_min_number_thread", CONF_ABONE_MIN_NUMBER_THREAD, 0, CONFIG::get_max_resnumber() );
+ abone_max_number_thread = cf.get_option_int( "abone_number_thread", CONF_ABONE_MAX_NUMBER_THREAD, 0, CONFIG::get_max_resnumber() );
// スレ あぼーん( スレ立てからの経過時間 )
abone_hour_thread = cf.get_option_int( "abone_hour_thread", CONF_ABONE_HOUR_THREAD, 0, 9999 );
@@ -591,6 +591,9 @@ bool ConfigItems::load( const bool restore )
// 状態変更時にメインステータスバーの色を変える
change_stastatus_color = cf.get_option_bool( "change_stastatus_color", CONF_CHANGE_STASTATUS_COLOR );
+ // 状態変更時にスレビュータイトルの色を変える
+ change_statitle_color = cf.get_option_bool( "change_statitle_color", CONF_CHANGE_STATITLE_COLOR );
+
// まちBBSの取得に offlaw.cgi を使用する
use_machi_offlaw = cf.get_option_bool( "use_machi_offlaw", CONF_USE_MACHI_OFFLAW );
@@ -614,6 +617,12 @@ bool ConfigItems::load( const bool restore )
migemodict_path = cf.get_option_str( "migemodict_path", CONF_MIGEMO_PATH );
#endif
+ // 不正なMS932文字列をUTF-8と見なす
+ broken_sjis_be_utf8 = cf.get_option_bool( "broken_sjis_be_utf8", CONF_BROKEN_SJIS_BE_UTF8 );
+
+ // 不正な数値文字参照を無理矢理変換する
+ correct_character_reference = cf.get_option_bool( "correct_character_reference", CONF_CORRECT_CHAR_REFERENCE );
+
m_loaded = true;
// 設定値に壊れている物がある
@@ -653,7 +662,6 @@ bool ConfigItems::load( const bool restore )
void ConfigItems::save()
{
save_impl( CACHE::path_conf() );
- if( CACHE::file_exists( CACHE::path_conf_old() ) == CACHE::EXIST_FILE ) save_impl( CACHE::path_conf_old() );
}
@@ -684,8 +692,6 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "regex_search_title", regex_search_title );
cf.update( "menu_search_web", menu_search_web );
cf.update( "url_search_web", url_search_web );
- cf.update( "url_writep2", url_writep2 );
- cf.update( "url_resp2", url_resp2 );
cf.update( "fontname_main", fontname[ FONT_MAIN ] );
cf.update( "fontname_popup", fontname[ FONT_POPUP ] );
@@ -735,13 +741,17 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "loader_timeout_checkupdate", loader_timeout_checkupdate );
cf.update( "use_ipv6", use_ipv6 );
+ cf.update( "tls_nonblocking", tls_nonblocking );
+ cf.update( "verify_cert", verify_cert );
+ cf.update( "root_cafile", root_cafile );
cf.update( "connection_num", connection_num );
cf.update( "use_cookie_hap", use_cookie_hap );
cf.update( "cookie_hap", cookie_hap );
cf.update( "cookie_hap_bbspink", cookie_hap_bbspink );
- cf.update( "use_offlaw2_2ch", use_offlaw2_2ch );
+ cf.update( "use_external_log", use_external_log );
+ cf.update( "url_external_log", url_external_log );
cf.update( "command_openurl", command_openurl );
cf.update( "browsercombo_id", browsercombo_id );
@@ -812,6 +822,7 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "use_message_gtktheme", use_message_gtktheme );
cf.update( "use_tree_gtkrc", use_tree_gtkrc );
cf.update( "use_select_gtkrc", use_select_gtkrc );
+ cf.update( "use_color_html", use_color_html );
cf.update( "tree_ypad", tree_ypad );
cf.update( "tree_show_expanders", tree_show_expanders );
@@ -886,6 +897,8 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "loose_url", loose_url );
+ cf.update( "percent_decode", percent_decode );
+
cf.update( "hide_usrcmd", hide_usrcmd );
cf.update( "reload_allthreads", reload_allthreads );
@@ -915,7 +928,8 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "remove_old_abone_thread", remove_old_abone_thread );
- cf.update( "abone_number_thread", abone_number_thread );
+ cf.update( "abone_min_number_thread", abone_min_number_thread );
+ cf.update( "abone_number_thread", abone_max_number_thread );
cf.update( "abone_hour_thread", abone_hour_thread );
// あぼーん情報
@@ -949,6 +963,7 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "disable_close", disable_close );
cf.update( "show_hide_menubar_diag", show_hide_menubar_diag );
cf.update( "change_stastatus_color", change_stastatus_color );
+ cf.update( "change_statitle_color", change_statitle_color );
cf.update( "use_machi_offlaw", use_machi_offlaw );
cf.update( "show_del_written_thread_diag", show_del_written_thread_diag );
cf.update( "delete_img_in_thread", delete_img_in_thread );
@@ -960,6 +975,9 @@ void ConfigItems::save_impl( const std::string& path )
cf.update( "migemodict_path", migemodict_path );
#endif
+ cf.update( "broken_sjis_be_utf8", broken_sjis_be_utf8 );
+ cf.update( "correct_character_reference", correct_character_reference );
+
cf.save();
}
diff --git a/src/config/configitems.h b/src/config/configitems.h
index f89e4392..a16afe01 100644
--- a/src/config/configitems.h
+++ b/src/config/configitems.h
@@ -91,6 +91,15 @@ namespace CONFIG
// ipv6使用
bool use_ipv6;
+ // TLSでノンブロッキングI/Oを使用する
+ bool tls_nonblocking;
+
+ // TLSでサーバの証明書をチェックする
+ bool verify_cert;
+
+ // 信頼するルート証明書
+ std::string root_cafile;
+
// 同一ホストに対する最大コネクション数( 1 または 2 )
int connection_num;
@@ -101,8 +110,9 @@ namespace CONFIG
std::string cookie_hap;
std::string cookie_hap_bbspink;
- // 2chの過去ログ取得時にofflaw2を使用する
- bool use_offlaw2_2ch;
+ // 2chの過去ログを外部のサイトから取得する
+ bool use_external_log;
+ std::string url_external_log;
// リンクをクリックしたときに実行するコマンド
std::string command_openurl;
@@ -211,10 +221,6 @@ namespace CONFIG
std::string menu_search_web;
std::string url_search_web;
- // p2 書き込み用アドレス
- std::string url_writep2;
- std::string url_resp2;
-
// 色
std::vector< std::string > str_color;
@@ -227,6 +233,9 @@ namespace CONFIG
// スレビューの選択色でgtkrcの設定を使用するか
bool use_select_gtkrc;
+ // スレビューでHTMLタグ指定の色を使用するか
+ bool use_color_html;
+
// ツリービューの行間スペース
int tree_ypad;
@@ -403,6 +412,9 @@ namespace CONFIG
// datのパース時にURL判定を甘くする(^なども含める)
bool loose_url;
+ // URLのパーセントコードをデコードして表示する
+ bool percent_decode;
+
// ユーザーコマンドで選択できない項目を非表示にする
bool hide_usrcmd;
@@ -446,7 +458,8 @@ namespace CONFIG
int remove_old_abone_thread;
// スレ あぼーん レス数
- int abone_number_thread;
+ int abone_min_number_thread;
+ int abone_max_number_thread;
// スレ あぼーん スレ立てからの経過時間
int abone_hour_thread;
@@ -510,6 +523,9 @@ namespace CONFIG
// 状態変更時にメインステータスバーの色を変える
bool change_stastatus_color;
+ // 状態変更時にスレビュータイトルの色を変える
+ bool change_statitle_color;
+
// まちBBSの取得に offlaw.cgi を使用する
bool use_machi_offlaw;
@@ -533,6 +549,12 @@ namespace CONFIG
std::string migemodict_path;
#endif
+ // 不正なMS932文字列をUTF-8と見なす
+ bool broken_sjis_be_utf8;
+
+ // 不正な数値文字参照を無理矢理変換する
+ bool correct_character_reference;
+
/////////////////////////
diff --git a/src/config/defaultconf.h b/src/config/defaultconf.h
index bbb610a1..44c80237 100644
--- a/src/config/defaultconf.h
+++ b/src/config/defaultconf.h
@@ -35,15 +35,18 @@ namespace CONFIG
CONF_LOADER_TIMEOUT_IMG = 30, // 画像ローダのタイムアウト値
CONF_LOADER_TIMEOUT_CHECKUPDATE = 10, // 更新チェックのタイムアウト値
CONF_USE_IPV6 = 1, // ipv6使用
+ CONF_TLS_NONBLOCKING = 1, // TLSでノンブロッキングI/Oを使用する
+ CONF_VERIFY_CERT = 1, // TLSでサーバの証明書をチェックする
CONF_CONNECTION_NUM = 2, // 同一ホストに対する最大コネクション数( 1 または 2 )
CONF_USE_COOKIE_HAP = 0, // 2chのクッキー:HAPを保存する
- CONF_USE_OFFLAW2_2CH = 0, // 2chの過去ログ取得時にofflaw2を使用する
+ CONF_USE_EXTERNAL_LOG = 0, // 2chの過去ログを外部サイトから取得する
CONF_REFPOPUP_BY_MO = 0, // レス番号の上にマウスオーバーしたときに参照ポップアップ表示する
CONF_NAMEPOPUP_BY_MO = 0, // 名前の上にマウスオーバーしたときにポップアップ表示する
CONF_IDPOPUP_BY_MO = 0, // IDの上にマウスオーバーしたときにIDをポップアップ表示する
CONF_USE_MESSAGE_GTKTHEME = 0, // 書き込みビューでGTKテーマの設定を使用するか (GTK3版のみ)
CONF_USE_TREE_GTKRC = 0, // ツリービューでgtkrcの設定を使用するか
CONF_USE_SELECT_GTKRC = 0, // スレビューの選択色でgtkrcの設定を使用するか
+ CONF_USE_COLOR_HTML = 1, // スレビューでHTMLタグ指定の色を使用するか
CONF_TREE_YPAD = 1, // ツリービューの行間スペース
CONF_TREE_SHOW_EXPANDERS = 1, // ツリービューにエクスパンダを表示
CONF_TREE_LEVEL_INDENT = 0, // ツリービューのレベルインデント調整量(ピクセル)
@@ -101,6 +104,7 @@ namespace CONFIG
CONF_NUM_ID_HIGH = 4, // 発言数で色を変える回数 (高)
CONF_NUM_ID_LOW = 2, // 発言数で色を変える回数 (低)
CONF_LOOSE_URL = 1, // datのパース時にURL判定を甘くする(^なども含める)
+ CONF_PERCENT_DECODE = 0, // URLのパーセントコードをデコードして表示する
CONF_HIDE_USRCMD = 0, // ユーザーコマンドで選択できない項目を非表示にする
CONF_RELOAD_ALLTHREAD = 0, // スレビューで再読み込みボタンを押したときに全タブを更新する
CONF_TAB_MIN_STR = 4, // タブに表示する文字列の最小値
@@ -136,7 +140,8 @@ namespace CONFIG
CONF_USE_LINK_AS_BOARD = 0, // bbsmenu.html内にあるリンクは全て板とみなす
CONF_SHOW_MOVEDIAG = 1, // 板移転時に確認ダイアログを表示する
CONF_REMOVE_OLD_ABONE_THREAD = 0, // dat落ちしたスレをNGスレタイトルリストから取り除くか( 0: ダイアログ表示 1: 取り除く 2: 除かない )
- CONF_ABONE_NUMBER_THREAD = 0, // スレあぼーん( レス数 )
+ CONF_ABONE_MIN_NUMBER_THREAD = 0, // スレあぼーん( レス数(最小) )
+ CONF_ABONE_MAX_NUMBER_THREAD = 0, // スレあぼーん( レス数(最大) )
CONF_ABONE_HOUR_THREAD = 0, // スレあぼーん( スレ立てからの経過時間 )
CONF_ABONE_TRANSPARENT = 0, // デフォルトで透明あぼーんをする
CONF_ABONE_CHAIN = 0, // デフォルトで連鎖あぼーんをする
@@ -156,12 +161,15 @@ namespace CONFIG
CONF_DISABLE_CLOSE = 0, // Ctrl+qでウィンドウを閉じない
CONF_SHOW_HIDE_MENUBAR_DIAG = 1, // メニューバーを非表示にした時にダイアログを表示
CONF_CHANGE_STASTATUS_COLOR = 1, // 状態変更時にメインステータスバーの色を変える
+ CONF_CHANGE_STATITLE_COLOR = 1, // 状態変更時にスレビュータイトルの色を変える
CONF_USE_MACHI_OFFLAW = 0, // まちBBSの取得に offlaw.cgi を使用する
CONF_SHOW_DEL_WRITTEN_THREAD_DIAG = 1, // 書き込み履歴のあるスレを削除する時にダイアログを表示
CONF_DELETE_IMG_IN_THREAD = 0, // スレを削除する時に画像キャッシュも削除する ( 0: ダイアログ表示 1: 削除 2: 削除しない )
CONF_MAX_RESNUMBER = 65536, //最大表示可能レス数
CONF_SHOW_DIAG_FIFO_ERROR = 1, // FIFOの作成などにエラーがあったらダイアログを表示する
CONF_SAVE_SESSION = 0, // 指定した分ごとにセッションを自動保存 (0: 保存しない)
+ CONF_BROKEN_SJIS_BE_UTF8 = 0, // 不正なMS932文字列をUTF-8と見なす
+ CONF_CORRECT_CHAR_REFERENCE = 0, // 不正な数値文字参照を無理矢理変換する
};
// browsers.cpp のデフォルトのラベル番号
@@ -194,10 +202,10 @@ namespace CONFIG
#define CONF_PATH_CACHEROOT "~/.jd/"
// 2ch にアクセスするときのエージェント名
-#define CONF_AGENT_FOR2CH "Monazilla/1.00 JD"
+#define CONF_AGENT_FOR2CH "Monazilla/1.00 JD/2.9"
// 2ch外にアクセスするときのエージェント名
-#define CONF_AGENT_FOR_DATA "Monazilla/1.00 JD"
+#define CONF_AGENT_FOR_DATA "Monazilla/1.00 JD/2.9"
// 2ch にログインするときのX-2ch-UA
#define CONF_X_2CH_UA "Navigator for 2ch 1.7.5"
@@ -215,7 +223,7 @@ namespace CONFIG
#define CONF_LOGINP2 "http://p2.2ch.sc/p2/"
// BEの認証サーバのアドレス
-#define CONF_LOGINBE "http://be.2ch.net/test/login.php"
+#define CONF_LOGINBE "http://be.5ch.net/test/login.php"
// bbsmenu.htmlのURL
#define CONF_URL_BBSMENU "http://menu.5ch.net/bbsmenu.html"
@@ -231,15 +239,13 @@ namespace CONFIG
#define CONF_MENU_SEARCH_WEB "WEB検索 (google)"
#define CONF_URL_SEARCH_WEB "http://www.google.co.jp/search?hl=ja&q=$TEXTU&btnG=Google+%E6%A4%9C%E7%B4%A2&lr="
-// p2 書き込み用アドレス
-
-#define CONF_URL_WRITEP2 "http://p2.2ch.sc/p2/post_form.php?host=$HOST&bbs=$BBSNAME&key=$DATNAME"
-#define CONF_URL_RESP2 "http://p2.2ch.sc/p2/post_form.php?host=$HOST&bbs=$BBSNAME&key=$DATNAME&popup=1&inyou=2&resnum=$NUMBER"
-
// 2chのクッキー:HAP
#define CONF_COOKIE_HAP ""
#define CONF_COOKIE_HAP_BBSPINK ""
+// 過去ログを取得する外部サイトのURL
+#define CONF_URL_EXTERNAL_LOG "http://mimizun.com/log/2ch/$BBSNAME/$DATNAME.dat"
+
// 色
#define CONF_COLOR_CHAR "#000000000000" // スレの文字
#define CONF_COLOR_CHAR_NAME "#000064640000" //名前欄の文字色
@@ -296,6 +302,13 @@ namespace CONFIG
#define CONF_MIGEMO_PATH "/usr/share/migemo/utf-8/migemo-dict"
#endif
+// TLSのルート証明書
+#ifdef DEFAULT_CAFILE
+#define CONF_ROOT_CAFILE DEFAULT_CAFILE
+#else
+#define CONF_ROOT_CAFILE "/etc/ssl/certs/ca-certificates.crt"
+#endif
+
}
#endif
diff --git a/src/config/globalconf.cpp b/src/config/globalconf.cpp
index 160605a2..219977ef 100644
--- a/src/config/globalconf.cpp
+++ b/src/config/globalconf.cpp
@@ -19,7 +19,6 @@ CONFIG::ConfigItems* instance_confitem_bkup = NULL;
CONFIG::ConfigItems* CONFIG::get_confitem()
{
- if( ! instance_confitem ) instance_confitem = new CONFIG::ConfigItems();
return instance_confitem;
}
@@ -36,6 +35,7 @@ void CONFIG::delete_confitem()
bool CONFIG::load_conf()
{
+ if( ! instance_confitem ) instance_confitem = new CONFIG::ConfigItems();
return get_confitem()->load();
}
@@ -97,6 +97,9 @@ void CONFIG::set_use_tree_gtkrc( const bool use ){ get_confitem()->use_tree_gtkr
bool CONFIG::get_use_select_gtkrc(){ return get_confitem()->use_select_gtkrc; }
void CONFIG::set_use_select_gtkrc( const bool use ){ get_confitem()->use_select_gtkrc = use; }
+bool CONFIG::get_use_color_html(){ return get_confitem()->use_color_html; }
+void CONFIG::set_use_color_html( const bool use ){ get_confitem()->use_color_html = use; }
+
// ツリービューの行間スペース
int CONFIG::get_tree_ypad(){ return get_confitem()->tree_ypad; }
@@ -182,9 +185,6 @@ const std::string& CONFIG::get_regex_search_title(){ return get_confitem()->rege
const std::string& CONFIG::get_menu_search_web(){ return get_confitem()->menu_search_web; }
const std::string& CONFIG::get_url_search_web(){ return get_confitem()->url_search_web; }
-const std::string& CONFIG::get_url_writep2(){ return get_confitem()->url_writep2; }
-const std::string& CONFIG::get_url_resp2(){ return get_confitem()->url_resp2; }
-
const std::string& CONFIG::get_agent_for2ch() { return get_confitem()->agent_for2ch; }
bool CONFIG::get_use_proxy_for2ch() { return get_confitem()->use_proxy_for2ch; }
@@ -229,6 +229,13 @@ int CONFIG::get_loader_timeout_checkupdate(){ return get_confitem()->loader_time
bool CONFIG::get_use_ipv6(){ return get_confitem()->use_ipv6; }
void CONFIG::set_use_ipv6( const bool set ){ get_confitem()->use_ipv6 = set; }
+// TLSでノンブロッキングI/Oを使用する
+bool CONFIG::get_tls_nonblocking(){ return get_confitem()->tls_nonblocking; }
+// TLSでサーバの証明書をチェックする
+bool CONFIG::get_verify_cert(){ return get_confitem()->verify_cert; }
+// 信頼するルート証明書
+const std::string& CONFIG::get_root_cafile(){ return get_confitem()->root_cafile; }
+
// 同一ホストに対する最大コネクション数( 1 または 2 )
int CONFIG::get_connection_num(){ return get_confitem()->connection_num; }
@@ -239,8 +246,14 @@ const std::string& CONFIG::get_cookie_hap_bbspink(){ return get_confitem()->cook
void CONFIG::set_cookie_hap( const std::string& cookie_hap ){ get_confitem()->cookie_hap = cookie_hap; }
void CONFIG::set_cookie_hap_bbspink( const std::string& cookie_hap ){ get_confitem()->cookie_hap_bbspink = cookie_hap; }
+#ifdef WITHOUT_5CH_API
// 2chの過去ログ取得時にofflaw2を使用する
bool CONFIG::get_use_offlaw2_2ch(){ return get_confitem()->use_offlaw2_2ch; }
+#endif
+
+// 2chの過去ログを外部のサイトから取得する
+bool CONFIG::get_use_external_log(){ return get_confitem()->use_external_log; }
+const std::string& CONFIG::get_url_external_log(){ return get_confitem()->url_external_log; }
const std::string& CONFIG::get_command_openurl() { return get_confitem()->command_openurl; }
void CONFIG::set_command_openurl( const std::string& command ){ get_confitem()->command_openurl = command; }
@@ -438,6 +451,8 @@ int CONFIG::get_num_id_low(){ return get_confitem()->num_id_low; }
bool CONFIG::get_loose_url(){ return get_confitem()->loose_url; }
+bool CONFIG::get_percent_decode(){ return get_confitem()->percent_decode; }
+
bool CONFIG::get_hide_usrcmd(){ return get_confitem()->hide_usrcmd; }
void CONFIG::set_hide_usrcmd( const bool hide ){ get_confitem()->hide_usrcmd = hide; }
@@ -492,8 +507,11 @@ void CONFIG::set_list_abone_regex_thread( std::list< std::string >& regex )
int CONFIG::get_remove_old_abone_thread(){ return get_confitem()->remove_old_abone_thread; }
void CONFIG::set_remove_old_abone_thread( const int remove ){ get_confitem()->remove_old_abone_thread = remove; }
-int CONFIG::get_abone_number_thread(){ return get_confitem()->abone_number_thread; }
-void CONFIG::set_abone_number_thread( const int number ){ get_confitem()->abone_number_thread = number; }
+int CONFIG::get_abone_min_number_thread(){ return get_confitem()->abone_min_number_thread; }
+void CONFIG::set_abone_min_number_thread( const int number ){ get_confitem()->abone_min_number_thread = number; }
+
+int CONFIG::get_abone_max_number_thread(){ return get_confitem()->abone_max_number_thread; }
+void CONFIG::set_abone_max_number_thread( const int number ){ get_confitem()->abone_max_number_thread = number; }
int CONFIG::get_abone_hour_thread(){ return get_confitem()->abone_hour_thread; }
void CONFIG::set_abone_hour_thread( const int hour ){ get_confitem()->abone_hour_thread = hour; }
@@ -586,6 +604,9 @@ void CONFIG::set_show_hide_menubar_diag( const bool set ){ get_confitem()->show_
// 状態変更時にメインステータスバーの色を変える
bool CONFIG::get_change_stastatus_color(){ return get_confitem()->change_stastatus_color; }
+// 状態変更時にスレビュータイトルの色を変える
+bool CONFIG::get_change_statitle_color(){ return get_confitem()->change_statitle_color; }
+
// まちBBSの取得に offlaw.cgi を使用する
bool CONFIG::get_use_machi_offlaw(){ return get_confitem()->use_machi_offlaw; }
void CONFIG::set_use_machi_offlaw( const bool set ){ get_confitem()->use_machi_offlaw = set; }
@@ -613,3 +634,12 @@ int CONFIG::get_save_session(){ return get_confitem()->save_session; }
#ifdef HAVE_MIGEMO_H
const std::string& CONFIG::get_migemodict_path() { return get_confitem()->migemodict_path; }
#endif
+
+// 不正なMS932文字列をUTF-8と見なす
+bool CONFIG::get_broken_sjis_be_utf8(){ return get_confitem()->broken_sjis_be_utf8; }
+void CONFIG::set_broken_sjis_be_utf8( const bool set ){ get_confitem()->broken_sjis_be_utf8 = set; }
+
+// 不正な数値文字参照を無理矢理変換する
+bool CONFIG::get_correct_character_reference(){ return get_confitem()->correct_character_reference; }
+void CONFIG::set_correct_character_reference( const bool set ){ get_confitem()->correct_character_reference = set; }
+
diff --git a/src/config/globalconf.h b/src/config/globalconf.h
index 5eb130e6..c9b44eac 100644
--- a/src/config/globalconf.h
+++ b/src/config/globalconf.h
@@ -56,6 +56,10 @@ namespace CONFIG
bool get_use_select_gtkrc();
void set_use_select_gtkrc( const bool use );
+ // スレビューでHTMLタグ指定の色を使用するか
+ bool get_use_color_html();
+ void set_use_color_html( const bool use );
+
// ツリービューの行間スペース
int get_tree_ypad();
@@ -133,10 +137,6 @@ namespace CONFIG
const std::string& get_menu_search_web();
const std::string& get_url_search_web();
- // p2 書き込み用アドレス
- const std::string& get_url_writep2();
- const std::string& get_url_resp2();
-
// 2ch にアクセスするときのエージェント名
const std::string& get_agent_for2ch();
@@ -190,6 +190,15 @@ namespace CONFIG
bool get_use_ipv6();
void set_use_ipv6( const bool set );
+ // TLSでノンブロッキングI/Oを使用する
+ bool get_tls_nonblocking();
+
+ // TLSでサーバの証明書をチェックする
+ bool get_verify_cert();
+
+ // 信頼するルート証明書
+ const std::string& get_root_cafile();
+
// 同一ホストに対する最大コネクション数( 1 または 2 )
int get_connection_num();
@@ -200,8 +209,14 @@ namespace CONFIG
void set_cookie_hap( const std::string& cookie_hap );
void set_cookie_hap_bbspink( const std::string& cookie_hap );
+#ifdef WITHOUT_5CH_API
// 2chの過去ログ取得時にofflaw2を使用する
bool get_use_offlaw2_2ch();
+#endif
+
+ // 2chの過去ログを外部のサイトから取得する
+ bool get_use_external_log();
+ const std::string& get_url_external_log();
// リンクをクリックしたときに実行するコマンド
const std::string& get_command_openurl();
@@ -453,6 +468,9 @@ namespace CONFIG
// datのパース時にURL判定を甘くする(^なども含める)
bool get_loose_url();
+ // URLのパーセントコードをデコードして表示する
+ bool get_percent_decode();
+
// ユーザーコマンドで選択できない項目を非表示にする
bool get_hide_usrcmd();
void set_hide_usrcmd( const bool hide );
@@ -500,8 +518,11 @@ namespace CONFIG
int get_remove_old_abone_thread(); // dat落ちしたスレをNGスレタイトルリストから取り除くか( 0: ダイアログ表示 1: 取り除く 2: 除かない )
void set_remove_old_abone_thread( const int remove );
- int get_abone_number_thread();
- void set_abone_number_thread( const int number );
+ int get_abone_min_number_thread();
+ void set_abone_min_number_thread( const int number );
+
+ int get_abone_max_number_thread();
+ void set_abone_max_number_thread( const int number );
int get_abone_hour_thread();
void set_abone_hour_thread( const int hour );
@@ -576,6 +597,9 @@ namespace CONFIG
// 状態変更時にメインステータスバーの色を変える
bool get_change_stastatus_color();
+ // 状態変更時にスレビュータイトルの色を変える
+ bool get_change_statitle_color();
+
// まちBBSの取得に offlaw.cgi を使用する
bool get_use_machi_offlaw();
void set_use_machi_offlaw( const bool set );
@@ -603,6 +627,14 @@ namespace CONFIG
// migemo-dictの場所
const std::string& get_migemodict_path();
#endif
+
+ // 不正なMS932文字列をUTF-8と見なす
+ bool get_broken_sjis_be_utf8();
+ void set_broken_sjis_be_utf8( const bool set );
+
+ // 不正な数値文字参照を無理矢理変換する
+ bool get_correct_character_reference();
+ void set_correct_character_reference( const bool set );
}
diff --git a/src/control/Makefile.am b/src/control/Makefile.am
index 2448b914..a58e56d1 100644
--- a/src/control/Makefile.am
+++ b/src/control/Makefile.am
@@ -14,8 +14,7 @@ noinst_HEADERS = \
controlutil.h \
mousekeyconf.h mousekeyitem.h keyconfig.h mouseconfig.h buttonconfig.h \
mousekeypref.h keypref.h mousepref.h buttonpref.h \
- defaultconf.h \
- get_config.h
+ defaultconf.h get_config.h
AM_CXXFLAGS = @GTKMM_CFLAGS@
AM_CPPFLAGS = -I$(top_srcdir)/src
diff --git a/src/control/buttonconfig.cpp b/src/control/buttonconfig.cpp
index fb75cb06..b5e959a6 100644
--- a/src/control/buttonconfig.cpp
+++ b/src/control/buttonconfig.cpp
@@ -23,8 +23,7 @@ ButtonConfig::ButtonConfig()
{}
-ButtonConfig::~ButtonConfig() noexcept
-{}
+ButtonConfig::~ButtonConfig() noexcept = default;
//
diff --git a/src/control/keyconfig.cpp b/src/control/keyconfig.cpp
index b91919fd..861e88bb 100644
--- a/src/control/keyconfig.cpp
+++ b/src/control/keyconfig.cpp
@@ -25,8 +25,7 @@ KeyConfig::KeyConfig()
{}
-KeyConfig::~KeyConfig() noexcept
-{}
+KeyConfig::~KeyConfig() noexcept = default;
diff --git a/src/control/mouseconfig.cpp b/src/control/mouseconfig.cpp
index 7be686ed..48945d98 100644
--- a/src/control/mouseconfig.cpp
+++ b/src/control/mouseconfig.cpp
@@ -23,9 +23,7 @@ MouseConfig::MouseConfig()
{}
-
-MouseConfig::~MouseConfig() noexcept
-{}
+MouseConfig::~MouseConfig() noexcept = default;
//
diff --git a/src/control/mousekeyconf.cpp b/src/control/mousekeyconf.cpp
index cb4cb2f1..d3735df4 100644
--- a/src/control/mousekeyconf.cpp
+++ b/src/control/mousekeyconf.cpp
@@ -20,10 +20,7 @@ MouseKeyConf::MouseKeyConf()
{}
-
-MouseKeyConf::~MouseKeyConf() noexcept
-{}
-
+MouseKeyConf::~MouseKeyConf() noexcept = default;
// 設定ファイル保存
diff --git a/src/core.cpp b/src/core.cpp
index be3877a5..73c8bf8a 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -14,6 +14,7 @@
#include "dndmanager.h"
#include "usrcmdmanager.h"
#include "linkfiltermanager.h"
+#include "replacestrmanager.h"
#include "compmanager.h"
#include "searchmanager.h"
#include "aamanager.h"
@@ -132,6 +133,9 @@ Core::Core( JDWinMain& win_main )
// リンクフィルタマネージャ作成
CORE::get_linkfilter_manager();
+ // 文字列置換マネージャ作成
+ CORE::get_replacestr_manager();
+
// ログ検索マネージャ作成
CORE::get_search_manager();
@@ -179,6 +183,9 @@ Core::~Core()
// ログ検索マネージャ削除
CORE::delete_search_manager();
+ // 文字列置換マネージャ削除
+ CORE::delete_replacestr_manager();
+
// ユーザコマンドマネージャ削除
CORE::delete_usrcmd_manager();
@@ -332,7 +339,7 @@ void Core::run( const bool init, const bool skip_setupdiag )
m_action_group->add( Gtk::Action::create( "OpenURL", "OpenURL"), sigc::mem_fun( *this, &Core::slot_openurl ) );
m_action_group->add( Gtk::ToggleAction::create( "Online", "オフライン作業(_W)", std::string(), ! SESSION::is_online() ),
sigc::mem_fun( *this, &Core::slot_toggle_online ) );
- m_action_group->add( Gtk::ToggleAction::create( "Login2ch", "2chにログイン(_L)", std::string(), false ),
+ m_action_group->add( Gtk::ToggleAction::create( "Login2ch", "5chにログイン(_L)", std::string(), false ),
sigc::mem_fun( *this, &Core::slot_toggle_login2ch ) );
m_action_group->add( Gtk::ToggleAction::create( "LoginBe", "BEにログイン(_B)", std::string(), false ),
sigc::mem_fun( *this, &Core::slot_toggle_loginbe ) );
@@ -577,11 +584,13 @@ void Core::run( const bool init, const bool skip_setupdiag )
m_action_group->add( raction_img1, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_imgview ), IMGVIEW_EMB ) );
m_action_group->add( raction_img2, sigc::bind< int >( sigc::mem_fun( *this, &Core::slot_toggle_imgview ), IMGVIEW_NO ) );
+ m_action_group->add( Gtk::ToggleAction::create( "UseMosaic", "画像にモザイクをかける(_M)", std::string(), CONFIG::get_use_mosaic() ),
+ sigc::mem_fun( *this, &Core::slot_toggle_use_mosaic ) );
m_action_group->add( Gtk::ToggleAction::create( "UseImgPopup", "画像ポップアップを表示する(_P)", std::string(), CONFIG::get_use_image_popup() ),
sigc::mem_fun( *this, &Core::slot_toggle_use_imgpopup ) );
m_action_group->add( Gtk::ToggleAction::create( "UseInlineImg", "インライン画像を表示する(_I)", std::string(), CONFIG::get_use_inline_image() ),
sigc::mem_fun( *this, &Core::slot_toggle_use_inlineimg ) );
- m_action_group->add( Gtk::ToggleAction::create( "ShowSsspIcon", "BEアイコン/エモーションを表示する(_B)", std::string(), CONFIG::get_show_ssspicon() ),
+ m_action_group->add( Gtk::ToggleAction::create( "ShowSsspIcon", "BEアイコン/エモティコンを表示する(_B)", std::string(), CONFIG::get_show_ssspicon() ),
sigc::mem_fun( *this, &Core::slot_toggle_show_ssspicon ) );
// リスト表示項目設定
@@ -646,8 +655,6 @@ void Core::run( const bool init, const bool skip_setupdiag )
m_action_group->add( Gtk::ToggleAction::create( "SavePostHist", "書き込み履歴(鉛筆マーク)を保存する(_P)", std::string(), CONFIG::get_save_post_history() ),
sigc::mem_fun( *this, &Core::slot_toggle_save_post_history ) );
- m_action_group->add( Gtk::ToggleAction::create( "UseMosaic", "画像にモザイクをかける(_M)", std::string(), CONFIG::get_use_mosaic() ),
- sigc::mem_fun( *this, &Core::slot_toggle_use_mosaic ) );
m_action_group->add( Gtk::ToggleAction::create( "UseMachiOfflaw", "まちBBSでofflaw.cgiを使用する(_O)", std::string(), CONFIG::get_use_machi_offlaw() ),
sigc::mem_fun( *this, &Core::slot_toggle_use_machi_offlaw ) );
@@ -715,6 +722,7 @@ void Core::run( const bool init, const bool skip_setupdiag )
m_action_group->add( Gtk::Action::create( "LivePref", "実況設定(_L)..." ), sigc::mem_fun( *this, &Core::slot_setup_live ) );
m_action_group->add( Gtk::Action::create( "UsrCmdPref", "ユーザコマンドの編集(_U)..." ), sigc::mem_fun( *this, &Core::slot_usrcmd_pref ) );
m_action_group->add( Gtk::Action::create( "FilterPref", "リンクフィルタの編集(_F)..." ), sigc::mem_fun( *this, &Core::slot_filter_pref ) );
+ m_action_group->add( Gtk::Action::create( "ReplacePref", "置換文字列の編集(_R)..." ), sigc::mem_fun( *this, &Core::slot_replace_pref ) );
m_action_group->add( Gtk::Action::create( "AboutConfig", "about:config 高度な設定(_C)..." ), sigc::mem_fun( *this, &Core::slot_aboutconfig ) );
@@ -930,6 +938,7 @@ void Core::run( const bool init, const bool skip_setupdiag )
"<menuitem action='UseEmbImg'/>"
"<menuitem action='NoUseImg'/>"
"</menu>"
+ "<menuitem action='UseMosaic'/>"
"<menuitem action='UseImgPopup'/>"
"<menuitem action='UseInlineImg'/>"
"<menuitem action='ShowSsspIcon'/>"
@@ -1011,8 +1020,6 @@ void Core::run( const bool init, const bool skip_setupdiag )
"<menuitem action='SavePostLog'/>"
"<menuitem action='SavePostHist'/>"
"<separator/>"
- "<menuitem action='UseMosaic'/>"
- "<separator/>"
"<menuitem action='UseMachiOfflaw'/>"
"</menu>"
"<separator/>"
@@ -1068,6 +1075,7 @@ void Core::run( const bool init, const bool skip_setupdiag )
"<menuitem action='LivePref'/>"
"<menuitem action='UsrCmdPref'/>"
"<menuitem action='FilterPref'/>"
+ "<menuitem action='ReplacePref'/>"
"</menu>"
"<separator/>"
"<menuitem action='AboutConfig'/>"
@@ -1381,7 +1389,7 @@ void Core::set_maintitle()
if( CORE::get_login2ch()->login_now() ) title +=" [ ● ]";
if( CORE::get_loginbe()->login_now() ) title +=" [ BE ]";
if( CORE::get_loginp2()->login_now() ) title +=" [ p2 ]";
- if( ! SESSION::is_online() ) title += " [ オフライン ]";
+ if( ! SESSION::is_online() ) title += " [ offline ]";
m_win_main.set_title( title );
}
@@ -1546,17 +1554,17 @@ void Core::slot_activate_menubar()
// 開いている板のログ検索
act = m_action_group->get_action( "SearchCacheBoard" );
- if( BOARD::get_admin()->empty() || DBTREE::url_subject( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false );
+ if( BOARD::get_admin()->empty() || DBTREE::url_boardbase( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false );
else act->set_sensitive( true );
// 開いている板のログ一覧表示
act = m_action_group->get_action( "ShowCacheBoard" );
- if( BOARD::get_admin()->empty() || DBTREE::url_subject( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false );
+ if( BOARD::get_admin()->empty() || DBTREE::url_boardbase( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false );
else act->set_sensitive( true );
// スレ一覧のプロパティ
act = m_action_group->get_action( "BoardPref" );
- if( BOARD::get_admin()->empty() || DBTREE::url_subject( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false );
+ if( BOARD::get_admin()->empty() || DBTREE::url_boardbase( BOARD::get_admin()->get_current_url() ).empty() ) act->set_sensitive( false );
else act->set_sensitive( true );
// スレのプロパティ
@@ -2296,10 +2304,6 @@ void Core::set_command( const COMMAND_ARGS& command )
}
}
- DBTREE::delete_article( command.url, ( command.arg1 == "reget" ) );
-
- if( DBTREE::article_is_cached( command.url ) ) return;
-
ARTICLE::get_admin()->set_command( "unlock_views", command.url );
ARTICLE::get_admin()->set_command( "close_view", command.url,
"closeall" // command.url を含む全てのビューを閉じる
@@ -2310,6 +2314,10 @@ void Core::set_command( const COMMAND_ARGS& command )
"closeall" // command.url を含む全てのビューを閉じる
);
+ DBTREE::delete_article( command.url, ( command.arg1 == "reget" ) );
+
+ if( DBTREE::article_is_cached( command.url ) ) return;
+
// ポップアップも削除して対象となるarticlebaseのロックを解除 (注) ポップアップは遅延してdeleteされる
// そうしないと articlebase::unlock_impl()が呼び出されないためnotetreebaseが削除されない
ARTICLE::get_admin()->set_command( "delete_all_popups" );
@@ -2336,7 +2344,7 @@ void Core::set_command( const COMMAND_ARGS& command )
// 全articleviewの再レイアウト
else if( command.command == "relayout_all_article" ){
- ARTICLE::get_admin()->set_command( "relayout_all" );
+ ARTICLE::get_admin()->set_command( "relayout_all", command.url, command.arg1 );
}
// 全articleviewのフォントの初期化
@@ -3260,7 +3268,7 @@ void Core::exec_command()
int num_from, num_to;
std::string num_str;
const std::string url_dat = DBTREE::url_dat( command.url, num_from, num_to, num_str );
- const std::string url_subject = DBTREE::url_subject( command.url );
+ const std::string boardbase = DBTREE::url_boardbase( command.url );
// datの場合ビューで開く
if( ! url_dat.empty() ){
@@ -3300,13 +3308,13 @@ void Core::exec_command()
}
// 掲示板のベースURLの場合
- else if( ! url_subject.empty() ){
+ else if( ! boardbase.empty() ){
#ifdef _DEBUG
- std::cout << "exec : open_board url = " << url_subject << std::endl;
+ std::cout << "exec : open_board url = " << boardbase << std::endl;
#endif
- CORE::core_set_command( "open_board" , url_subject, "true" );
+ CORE::core_set_command( "open_board" , boardbase, "true" );
}
// その他
@@ -4285,10 +4293,10 @@ void Core::import_dat( const std::string& url_board, const std::vector< std::str
{
if( ! list_files.size() ) return;
- const std::string url_subject = DBTREE::url_subject( url_board );
+ const std::string boardbase = DBTREE::url_boardbase( url_board );
#ifdef _DEBUG
- std::cout << "Core::import_dat url = " << url_subject << std::endl;
+ std::cout << "Core::import_dat url = " << boardbase << std::endl;
#endif
CORE::DATA_INFO_LIST list_info;
@@ -4301,7 +4309,7 @@ void Core::import_dat( const std::string& url_board, const std::vector< std::str
std::cout << filename << std::endl;
#endif
- std::string url = DBTREE::board_import_dat( url_subject, filename );
+ std::string url = DBTREE::board_import_dat( boardbase, filename );
if( ! url.empty() ){
info.url = url;
list_info.push_back( info );
@@ -4310,10 +4318,10 @@ void Core::import_dat( const std::string& url_board, const std::vector< std::str
if( list_info.size() ){
- CORE::core_set_command( "open_board" , url_subject, "true" , "auto" );
+ CORE::core_set_command( "open_board" , boardbase, "true" , "auto" );
CORE::SBUF_set_list( list_info );
- BOARD::get_admin()->set_command( "draw_bg_articles", url_subject );
+ BOARD::get_admin()->set_command( "draw_bg_articles", boardbase );
}
}
diff --git a/src/core.h b/src/core.h
index e53aa272..0a5c5b0a 100644
--- a/src/core.h
+++ b/src/core.h
@@ -314,6 +314,7 @@ namespace CORE
void slot_setup_live();
void slot_usrcmd_pref();
void slot_filter_pref();
+ void slot_replace_pref();
void slot_aboutconfig();
void slot_clear_privacy();
void slot_clear_post_log();
diff --git a/src/cssmanager.cpp b/src/cssmanager.cpp
index fc6232ad..8e3dbae6 100644
--- a/src/cssmanager.cpp
+++ b/src/cssmanager.cpp
@@ -85,7 +85,7 @@ void Css_Manager::clear_property( CSS_PROPERTY* css )
//
// ユーザ設定の色取得
//
-std::string Css_Manager::get_color( int colorid )
+std::string Css_Manager::get_color( int colorid ) const
{
colorid -= USRCOLOR_BASE;
return m_colors[ colorid ];
@@ -95,11 +95,11 @@ std::string Css_Manager::get_color( int colorid )
//
// クラス名からID取得
//
-int Css_Manager::get_classid( const std::string& classname )
+int Css_Manager::get_classid( const std::string& classname ) const
{
int id = 0;
- std::list< std::string >::iterator it = m_css_class.begin();
+ std::list< std::string >::const_iterator it = m_css_class.begin();
for( ; it != m_css_class.end(); ++it, ++id ) if( ( *it ) == classname ) return id;
return -1;
@@ -202,6 +202,15 @@ void Css_Manager::set_default_css()
css.border_bottom_width_px = 1;
set_property( "imgpopup", css );
+
+
+ /////////////////
+ // mark
+ std::map< std::string, std::string > pair;
+ pair.insert( make_pair( std::string( "color"), std::string( "black" ) ) );
+ pair.insert( make_pair( std::string( "background-color" ), std::string( "yellow" ) ) );
+
+ set_property( "mark", create_property( pair ) );
}
@@ -546,7 +555,7 @@ void Css_Manager::set_property( const std::string& classname, const CSS_PROPERTY
//
// 文字の高さを与えてemをセット
//
-void Css_Manager::set_size( CSS_PROPERTY* css, double height )
+void Css_Manager::set_size( CSS_PROPERTY* css, double height ) const
{
if( ! css ) return;
if( ! height ) return;
@@ -665,7 +674,7 @@ DOM* Css_Manager::create_textnode( const char* text )
#endif
DOM* tmpdom = create_domnode( DOMNODE_TEXT );
- tmpdom->chardat = ( char* ) m_heap.heap_alloc( lng );
+ tmpdom->chardat = ( char* ) m_heap.heap_alloc( lng + 1 );
strncpy( tmpdom->chardat, text, lng );
return tmpdom;
diff --git a/src/cssmanager.h b/src/cssmanager.h
index 563333c9..7dc9ce6d 100644
--- a/src/cssmanager.h
+++ b/src/cssmanager.h
@@ -147,22 +147,22 @@ namespace CORE
public:
Css_Manager();
- virtual ~Css_Manager() noexcept {}
+ virtual ~Css_Manager() noexcept = default;
// ユーザ設定の色取得
- std::string get_color( int colorid );
+ std::string get_color( int colorid ) const;
// ユーザ設定の色( 先頭は黒 )
std::vector< std::string >& get_colors() { return m_colors; }
// クラス名からID取得
- int get_classid( const std::string& classname );
+ int get_classid( const std::string& classname ) const;
// プロパティ取得
CSS_PROPERTY get_property( const int id );
// 文字の高さを与えてemをセット
- void set_size( CSS_PROPERTY* css, double height );
+ void set_size( CSS_PROPERTY* css, double height ) const;
// DOM 取得
const DOM* get_dom() const { return m_dom; }
diff --git a/src/dbimg/delimgdiag.h b/src/dbimg/delimgdiag.h
index 7a56187a..93184732 100644
--- a/src/dbimg/delimgdiag.h
+++ b/src/dbimg/delimgdiag.h
@@ -119,7 +119,7 @@ namespace DBIMG
show_all_children();
}
- ~DelImgDiag() noexcept {}
+ ~DelImgDiag() noexcept = default;
};
}
diff --git a/src/dbtree/article2ch.cpp b/src/dbtree/article2ch.cpp
index 0e38ab06..cfda3afb 100644
--- a/src/dbtree/article2ch.cpp
+++ b/src/dbtree/article2ch.cpp
@@ -7,6 +7,7 @@
#include "nodetree2ch.h"
#include "interface.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/misctime.h"
@@ -20,14 +21,12 @@
using namespace DBTREE;
-Article2ch::Article2ch( const std::string& datbase, const std::string& id, bool cached )
- : Article2chCompati( datbase, id, cached )
+Article2ch::Article2ch( const std::string& datbase, const std::string& id, bool cached, const CharCode charcode )
+ : Article2chCompati( datbase, id, cached, charcode )
{}
-Article2ch::~Article2ch() noexcept
-{}
-
+Article2ch::~Article2ch() noexcept = default;
// 書き込みメッセージ変換
@@ -35,41 +34,39 @@ std::string Article2ch::create_write_message( const std::string& name, const std
{
if( msg.empty() ) return std::string();
- const std::string charset = DBTREE::board_charset( get_url() );
-
std::stringstream ss_post;
ss_post.clear();
ss_post << "bbs=" << DBTREE::board_id( get_url() )
<< "&key=" << get_key();
// キーワード( hana=mogera や suka=pontan など )
- const std::string keyword = DBTREE::board_keyword_for_write( get_url() );
+ const std::string& keyword = DBTREE::board_keyword_for_write( get_url() );
if( ! keyword.empty() ) ss_post << "&" << keyword;
// ログイン中
- if( CORE::get_login2ch()->login_now() ){
- std::string sid = CORE::get_login2ch()->get_sessionid();
- ss_post << "&sid=" << MISC::url_encode( sid.c_str(), sid.length() );
+ if( CORE::get_login2ch()->login_now() && ! CORE::get_login2ch()->get_username().empty() ){
+ std::string sid = CORE::get_login2ch()->get_sessionid();
+ ss_post << "&sid=" << MISC::url_encode( sid );
}
ss_post << "&time=" << get_time_modified()
- << "&submit=" << MISC::charset_url_encode( "書き込む", charset )
- << "&FROM=" << MISC::charset_url_encode( name, charset )
- << "&mail=" << MISC::charset_url_encode( mail, charset )
- << "&MESSAGE=" << MISC::charset_url_encode( msg, charset );
+ << "&submit=" << MISC::url_encode( std::string( "書き込む" ), get_charcode() )
+ << "&FROM=" << MISC::url_encode( name, get_charcode() )
+ << "&mail=" << MISC::url_encode( mail, get_charcode() )
+ << "&MESSAGE=" << MISC::url_encode( msg, get_charcode() );
if( CORE::get_loginp2()->login_now() ){
- ss_post << "&detect_hint=" << MISC::charset_url_encode( "◎◇", charset )
+ ss_post << "&detect_hint=" << MISC::url_encode( std::string( "◎◇" ), get_charcode() )
<< "&host=" << MISC::url_encode( MISC::get_hostname( get_url(), false ) )
<< "&popup=1"
<< "&rescount=" << get_number_load()
- << "&ttitle_en=" << MISC::url_encode( MISC::base64( MISC::Iconv( MISC::remove_space( get_subject() ), "UTF-8", charset ) ) )
+ << "&ttitle_en=" << MISC::url_encode( MISC::base64( MISC::Iconv( get_subject(), CHARCODE_UTF8, get_charcode() ) ) )
<< "&csrfid=" << MISC::url_encode( CORE::get_loginp2()->get_sessiondata() );
}
#ifdef _DEBUG
- std::cout << "Article2chCompati::create_write_message " << ss_post.str() << std::endl;
+ std::cout << "Article2ch::create_write_message " << ss_post.str() << std::endl;
#endif
return ss_post.str();
@@ -118,7 +115,7 @@ NodeTreeBase* Article2ch::create_nodetree()
bool Article2ch::is_load_olddat()
{
// 2chにログインしている場合
- // または、offlaw2を使う設定の場合 ( bbspinkを除く )
- return CORE::get_login2ch()->login_now()
- || ( CONFIG::get_use_offlaw2_2ch() && get_url().find( ".bbspink.com" ) == std::string::npos );
+ // または、read.cgiを使う設定の場合
+ return ( CORE::get_login2ch()->login_now() && ! CORE::get_login2ch()->get_username().empty() )
+ || CONFIG::get_use_external_log();
}
diff --git a/src/dbtree/article2ch.h b/src/dbtree/article2ch.h
index ad84e40b..48954544 100644
--- a/src/dbtree/article2ch.h
+++ b/src/dbtree/article2ch.h
@@ -15,7 +15,7 @@ namespace DBTREE
{
public:
- Article2ch( const std::string& datbase, const std::string& id, bool cached );
+ Article2ch( const std::string& datbase, const std::string& id, bool cached, const CharCode charcode );
~Article2ch() noexcept;
// 書き込みメッセージ変換
diff --git a/src/dbtree/article2chcompati.cpp b/src/dbtree/article2chcompati.cpp
index d00be054..d99d3c68 100644
--- a/src/dbtree/article2chcompati.cpp
+++ b/src/dbtree/article2chcompati.cpp
@@ -16,8 +16,8 @@
using namespace DBTREE;
-Article2chCompati::Article2chCompati( const std::string& datbase, const std::string& _id, bool cached )
- : ArticleBase( datbase, _id, cached )
+Article2chCompati::Article2chCompati( const std::string& datbase, const std::string& _id, bool cached, const CharCode charcode )
+ : ArticleBase( datbase, _id, cached, charcode )
{
assert( ! get_id().empty() );
@@ -34,10 +34,7 @@ Article2chCompati::Article2chCompati( const std::string& datbase, const std::str
}
-
-Article2chCompati::~Article2chCompati() noexcept
-{}
-
+Article2chCompati::~Article2chCompati() noexcept = default;
// 書き込みメッセージ変換
@@ -45,17 +42,15 @@ std::string Article2chCompati::create_write_message( const std::string& name, co
{
if( msg.empty() ) return std::string();
- std::string charset = DBTREE::board_charset( get_url() );
-
std::stringstream ss_post;
ss_post.clear();
ss_post << "bbs=" << DBTREE::board_id( get_url() )
<< "&key=" << get_key()
<< "&time=" << get_time_modified()
- << "&submit=" << MISC::charset_url_encode( "書き込む", charset )
- << "&FROM=" << MISC::charset_url_encode( name, charset )
- << "&mail=" << MISC::charset_url_encode( mail, charset )
- << "&MESSAGE=" << MISC::charset_url_encode( msg, charset );
+ << "&submit=" << MISC::url_encode( std::string( "書き込む" ), get_charcode() )
+ << "&FROM=" << MISC::url_encode( name, get_charcode() )
+ << "&mail=" << MISC::url_encode( mail, get_charcode() )
+ << "&MESSAGE=" << MISC::url_encode( msg, get_charcode() );
#ifdef _DEBUG
std::cout << "Article2chCompati::create_write_message " << ss_post.str() << std::endl;
diff --git a/src/dbtree/article2chcompati.h b/src/dbtree/article2chcompati.h
index 2030730b..eea39aac 100644
--- a/src/dbtree/article2chcompati.h
+++ b/src/dbtree/article2chcompati.h
@@ -15,7 +15,7 @@ namespace DBTREE
{
public:
- Article2chCompati( const std::string& datbase, const std::string& id, bool cached );
+ Article2chCompati( const std::string& datbase, const std::string& id, bool cached, const CharCode charcode );
~Article2chCompati() noexcept;
// 書き込みメッセージ変換
diff --git a/src/dbtree/articlebase.cpp b/src/dbtree/articlebase.cpp
index c06e498d..837c7182 100644
--- a/src/dbtree/articlebase.cpp
+++ b/src/dbtree/articlebase.cpp
@@ -9,6 +9,7 @@
#include "skeleton/msgdiag.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/misctime.h"
#include "jdlib/miscmsg.h"
@@ -24,6 +25,7 @@
#include "cache.h"
#include "global.h"
#include "login2ch.h"
+#include "replacestrmanager.h"
#include "session.h"
#include "updatemanager.h"
@@ -59,7 +61,7 @@ if( it2 != lines.end() ){ \
-ArticleBase::ArticleBase( const std::string& datbase, const std::string& id, bool cached )
+ArticleBase::ArticleBase( const std::string& datbase, const std::string& id, bool cached, const CharCode charcode )
: SKELETON::Lockable(),
m_id ( id ),
m_key( std::string() ),
@@ -68,6 +70,7 @@ ArticleBase::ArticleBase( const std::string& datbase, const std::string& id, boo
m_code( HTTP_INIT ),
m_str_code( std::string() ),
m_status( STATUS_UNKNOWN ),
+ m_charcode( charcode ),
m_subject( std::string() ),
m_number( 0 ),
m_number_diff( 0 ),
@@ -81,6 +84,8 @@ ArticleBase::ArticleBase( const std::string& datbase, const std::string& id, boo
m_abone_transparent( false ),
m_abone_chain( false ),
m_abone_age( false ),
+ m_abone_default_name( false ),
+ m_abone_noid( false ),
m_abone_board( true ),
m_abone_global( true ),
m_bookmarked_thread( false ),
@@ -340,15 +345,6 @@ std::string ArticleBase::get_res_str( int number, bool ref )
}
-//
-// number 番のレスの生文字列を返す
-//
-std::string ArticleBase::get_raw_res_str( int number )
-{
- return get_nodetree()->get_raw_res_str( number );
-}
-
-
//
// 更新時刻
//
@@ -356,7 +352,7 @@ time_t ArticleBase::get_time_modified()
{
time_t time_out;
time_out = MISC::datetotime( m_date_modified );
- if( time_out == 0 ) time_out = time( NULL ) - 600;
+ if( time_out == 0 ) time_out = time( NULL ) - ( 60 * 60 );
return time_out;
}
@@ -458,25 +454,37 @@ void ArticleBase::reset_status()
}
+const std::string& ArticleBase::get_modified_subject( const bool renew )
+{
+ if( renew || m_modified_subject.empty() ){
+ CORE::ReplaceStr_Manager *mgr = CORE::get_replacestr_manager();
+
+ // タイトル文字列置換
+ if( mgr->list_size( CORE::REPLACETARGET_SUBJECT ) ){
+ m_modified_subject = mgr->replace( m_subject.c_str(), m_subject.length(), CORE::REPLACETARGET_SUBJECT );
+ }
+ else m_modified_subject = m_subject;
+
+ }
+
+ return m_modified_subject;
+}
+
+
void ArticleBase::set_subject( const std::string& subject )
{
if( subject.empty() ) return;
- // 特殊文字の置き換え
- if( subject.find( "&" ) != std::string::npos ){
+ std::string tmp_subject = MISC::remove_spaces( subject );
- std::string subject_tmp = MISC::html_unescape( subject );
-
- if( subject_tmp != m_subject ){
- m_subject = subject_tmp;
- m_save_info = true;
- }
- }
- else if( subject != m_subject ){
-
- m_subject = subject;
+ if( tmp_subject != m_subject ){
+ m_subject = tmp_subject;
m_save_info = true;
}
+
+ // 置換設定に変更がある場合も読み直すのでm_subjectが同じでも
+ // 次に読み込まれる時に生成させる為にクリア
+ m_modified_subject.clear();
}
@@ -500,7 +508,7 @@ void ArticleBase::set_number( const int number, const bool is_online )
// subject.txt に示されたレス数よりも実際の取得数の方が多い
else if( is_online && number < m_number ){
#ifdef _DEBUG
- std::cout << "ArticleBase::set_number : broken_subject " << get_subject() << " "
+ std::cout << "ArticleBase::set_number : broken_subject " << m_subject << " "
<< number << " / " << m_number << std::endl;
#endif
m_status |= STATUS_BROKEN_SUBJECT;
@@ -523,6 +531,15 @@ void ArticleBase::set_number_seen( const int number_seen )
}
+void ArticleBase::set_number_max( const int number_max )
+{
+ if( number_max != m_number_max ){
+ m_number_max = number_max;
+ m_save_info = true;
+ }
+}
+
+
// 最終書き込み時間( string型 )
const std::string& ArticleBase::get_write_date()
{
@@ -557,7 +574,7 @@ void ArticleBase::update_writetime()
m_save_info = true;
// BoardViewの行を更新
- CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id );
+ CORE::core_set_command( "update_board_item", DBTREE::url_boardbase( m_url ), m_id );
}
// 板の書き込み時間を更新
@@ -583,7 +600,7 @@ void ArticleBase::set_bookmarked_thread( const bool bookmarked )
save_info( true );
// BoardViewの行を更新
- CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id );
+ CORE::core_set_command( "update_board_item", DBTREE::url_boardbase( m_url ), m_id );
}
@@ -601,13 +618,17 @@ bool ArticleBase::enable_load()
//
bool ArticleBase::is_finished()
{
- if( is_cached() && ! enable_load() && m_number_max && get_number_seen() >= m_number_max ){
+ if( is_cached() && ! enable_load() ){
+ const int number_max = ( m_number_max != 0 ) ? m_number_max
+ : DBTREE::board_get_number_max_res( m_url );
+ if( number_max && m_number_load >= number_max ){
#ifdef _DEBUG
- std::cout << "ArticleBase::is_finished : seen = " << get_number_seen() << " max = " << m_number_max << " : " << get_subject() << std::endl;
+ std::cout << "ArticleBase::is_finished : load = " << m_number_load << " max = " << number_max << " : " << m_subject << std::endl;
#endif
- return true;
+ return true;
+ }
}
return false;
@@ -659,7 +680,8 @@ void ArticleBase::update_abone()
if( ! m_nodetree ) return;
get_nodetree()->copy_abone_info( m_list_abone_id, m_list_abone_name, m_list_abone_word, m_list_abone_regex, m_abone_reses,
- m_abone_transparent, m_abone_chain, m_abone_age, m_abone_board, m_abone_global );
+ m_abone_transparent, m_abone_chain, m_abone_age, m_abone_default_name, m_abone_noid,
+ m_abone_board, m_abone_global );
get_nodetree()->update_abone_all();
}
@@ -675,6 +697,7 @@ void ArticleBase::reset_abone( const std::list< std::string >& ids,
const std::list< std::string >& regexs,
const std::vector< char >& vec_abone_res,
const bool transparent, const bool chain, const bool age,
+ const bool default_name, const bool noid,
const bool board, const bool global
)
{
@@ -713,6 +736,8 @@ void ArticleBase::reset_abone( const std::list< std::string >& ids,
m_abone_transparent = transparent;
m_abone_chain = chain;
m_abone_age = age;
+ m_abone_default_name = default_name;
+ m_abone_noid = noid;
m_abone_board = board;
m_abone_global = global;
@@ -858,6 +883,36 @@ void ArticleBase::set_abone_age( const bool set )
}
+//
+// デフォルト名無しあぼーん更新
+//
+void ArticleBase::set_abone_default_name( const bool set )
+{
+ if( empty() ) return;
+
+ m_abone_default_name = set;
+
+ update_abone();
+
+ m_save_info = true;
+}
+
+
+//
+// ageあぼーん更新
+//
+void ArticleBase::set_abone_noid( const bool set )
+{
+ if( empty() ) return;
+
+ m_abone_noid = set;
+
+ update_abone();
+
+ m_save_info = true;
+}
+
+
//
// 板レベルでのあぼーんを有効にする
//
@@ -1024,7 +1079,8 @@ JDLIB::ConstPtr< NodeTreeBase >& ArticleBase::get_nodetree()
// あぼーん情報のコピー
m_nodetree->copy_abone_info( m_list_abone_id, m_list_abone_name, m_list_abone_word, m_list_abone_regex, m_abone_reses,
- m_abone_transparent, m_abone_chain, m_abone_age, m_abone_board, m_abone_global );
+ m_abone_transparent, m_abone_chain, m_abone_age, m_abone_default_name, m_abone_noid,
+ m_abone_board, m_abone_global );
// 書き込み情報のコピー
m_nodetree->copy_post_info( m_posts );
@@ -1080,7 +1136,7 @@ bool ArticleBase::is_loading() const
//
// 更新チェック中か
//
-bool ArticleBase::is_checking_update()
+bool ArticleBase::is_checking_update() const
{
if( ! is_loading() ) return false;
@@ -1178,6 +1234,9 @@ void ArticleBase::download_dat( const bool check_update )
return;
}
+ // 全レス既読ならロードしない
+ if( is_finished() ) return;
+
#ifdef _DEBUG
std::cout << "start\n";
#endif
@@ -1249,10 +1308,12 @@ void ArticleBase::copy_article_info( const std::string& url_src )
const bool transparent = DBTREE::get_abone_transparent( url_src );
const bool chain = DBTREE::get_abone_chain( url_src );
const bool age = DBTREE::get_abone_age( url_src );
+ const bool default_name = DBTREE::get_abone_default_name( url_src );
+ const bool noid = DBTREE::get_abone_noid( url_src );
const bool board = DBTREE::get_abone_board( url_src );
const bool global = DBTREE::get_abone_global( url_src );
- reset_abone( ids, names ,words, regexs, vec_abone_res, transparent, chain, age, board, global );
+ reset_abone( ids, names ,words, regexs, vec_abone_res, transparent, chain, age, default_name, noid, board, global );
}
@@ -1279,6 +1340,13 @@ void ArticleBase::slot_node_updated()
// スレの読み込み数更新
m_number_load = m_nodetree->get_res_number();
+ // スレの最大レス数更新
+ if( m_number_max == 0 ){
+ int res_max = m_nodetree->get_res_number_max();
+ if( res_max > 0 ) m_number_max = res_max;
+ else if( res_max == 0 ) m_number_max = CONFIG::get_max_resnumber();
+ }
+
// 対応するarticleビューを更新
CORE::core_set_command( "update_article", m_url );
}
@@ -1352,7 +1420,7 @@ void ArticleBase::slot_load_finished()
DBTREE::board_show_updateicon( m_url, true );
// スレ一覧の ! 行のアイコンを更新マークにする
- CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id );
+ CORE::core_set_command( "update_board_item", DBTREE::url_boardbase( m_url ), m_id );
}
// code と modified を戻しておく
@@ -1534,7 +1602,7 @@ void ArticleBase::slot_load_finished()
#endif
// 対応するBoardビューの行を更新
- CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id );
+ CORE::core_set_command( "update_board_item", DBTREE::url_boardbase( m_url ), m_id );
// articleビューに終了を知らせる
CORE::core_set_command( "update_article", m_url );
@@ -1623,7 +1691,7 @@ void ArticleBase::delete_cache( const bool cache_only )
if( m_bookmarked_thread ){
- const std::string msg = "「" + get_subject() +
+ const std::string msg = "「" + MISC::to_plain( get_modified_subject() ) +
"」にはしおりが付けられています。\n\nスレを削除しますか?\n\nしおりを解除するにはスレの上で右クリックしてしおり解除を選択してください。";
SKELETON::MsgDiag mdiag( NULL, msg, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO );
@@ -1633,7 +1701,7 @@ void ArticleBase::delete_cache( const bool cache_only )
if( CONFIG::get_show_del_written_thread_diag() && m_write_time.tv_sec ){
- const std::string msg = "「" + get_subject() + "」には書き込み履歴が残っています。\n\nスレを削除しますか?";
+ const std::string msg = "「" + MISC::to_plain( get_modified_subject() ) + "」には書き込み履歴が残っています。\n\nスレを削除しますか?";
SKELETON::MsgCheckDiag mdiag( NULL, msg,
"今後表示しない(常に削除)(_D)",
@@ -1649,11 +1717,11 @@ void ArticleBase::delete_cache( const bool cache_only )
bool delete_img_cache = false;
- std::list< std::string > list_urls = get_nodetree()->get_urls();
- std::list< std::string >::iterator it = list_urls.begin();
+ const std::list< std::string > list_urls = get_nodetree()->get_imglinks();
+ std::list< std::string >::const_iterator it = list_urls.begin();
for( ; it != list_urls.end(); ++it ){
- if( DBIMG::get_type_ext( *it ) != DBIMG::T_UNKNOWN && DBIMG::is_cached( *it ) ){
+ if( DBIMG::is_cached( *it ) ){
delete_img_cache = true;
break;
}
@@ -1663,7 +1731,7 @@ void ArticleBase::delete_cache( const bool cache_only )
if( CONFIG::get_delete_img_in_thread() == 0 ){
- const std::string msg = "「" + get_subject() + "」には画像が貼られています。\n\n画像のキャッシュも削除しますか?";
+ const std::string msg = "「" + MISC::to_plain( get_modified_subject() ) + "」には画像が貼られています。\n\n画像のキャッシュも削除しますか?";
SKELETON::MsgCheckDiag mdiag( NULL, msg,
"今後表示しない(常に削除しない)(_D)",
@@ -1688,7 +1756,7 @@ void ArticleBase::delete_cache( const bool cache_only )
it = list_urls.begin();
for( ; it != list_urls.end(); ++it ){
- if( DBIMG::get_type_ext( *it ) != DBIMG::T_UNKNOWN && DBIMG::is_cached( *it ) ){
+ if( DBIMG::is_cached( *it ) ){
#ifdef _DEBUG
std::cout << "delete " << *it << std::endl;
@@ -1732,6 +1800,8 @@ void ArticleBase::delete_cache( const bool cache_only )
m_abone_transparent = false;
m_abone_chain = false;
m_abone_age = false;
+ m_abone_default_name = false;
+ m_abone_noid = false;
m_abone_board = true;
m_abone_global = true;
m_read_info = false;
@@ -1753,7 +1823,7 @@ void ArticleBase::delete_cache( const bool cache_only )
if( CACHE::file_exists( path_dat ) == CACHE::EXIST_FILE ) unlink( to_locale_cstr( path_dat ) );
// BoardViewの行を更新
- CORE::core_set_command( "update_board_item", DBTREE::url_subject( m_url ), m_id );
+ CORE::core_set_command( "update_board_item", DBTREE::url_boardbase( m_url ), m_id );
// サイドバーのアイコン表示を戻す
CORE::core_set_command( "toggle_sidebar_articleicon", m_url );
@@ -1825,6 +1895,7 @@ void ArticleBase::read_info()
// subject
GET_INFOVALUE( m_subject, "subject = " );
+ m_modified_subject.clear(); // 読み込まれる時に生成
// 旧ホスト名
GET_INFOVALUE( m_org_host, "org_host = " );
@@ -1841,6 +1912,11 @@ void ArticleBase::read_info()
GET_INFOVALUE( str_tmp, "seen = " );
if( ! str_tmp.empty() ) m_number_seen = std::stoi( str_tmp );
+ // 最大レス数
+ m_number_max = 0;
+ GET_INFOVALUE( str_tmp, "max = " );
+ if( ! str_tmp.empty() ) m_number_max = atoi( str_tmp.c_str() );
+
// 更新時間 (time)
GET_INFOVALUE( m_date_modified, "modified = " );
@@ -1889,6 +1965,10 @@ void ArticleBase::read_info()
GET_INFOVALUE( str_tmp, "status = " );
if( ! str_tmp.empty() ) m_status = atoi( str_tmp.c_str() );
+ // charset
+ GET_INFOVALUE( str_tmp, "charset = " );
+ if( ! str_tmp.empty() ) set_charcode( MISC::charcode_from_cstr( str_tmp.c_str() ) );
+
// あぼーん ID
GET_INFOVALUE( str_tmp, "aboneid = " );
if( ! str_tmp.empty() ) m_list_abone_id = MISC::strtolist( str_tmp );
@@ -1962,6 +2042,16 @@ void ArticleBase::read_info()
GET_INFOVALUE( str_tmp, "aboneage = " );
if( ! str_tmp.empty() ) m_abone_age = atoi( str_tmp.c_str() );
+ // デフォルト名無しあぼーん
+ m_abone_default_name = false;
+ GET_INFOVALUE( str_tmp, "abonedefaultname = " );
+ if( ! str_tmp.empty() ) m_abone_default_name = atoi( str_tmp.c_str() );
+
+ // ID無しあぼーん
+ m_abone_noid = false;
+ GET_INFOVALUE( str_tmp, "abonenoid = " );
+ if( ! str_tmp.empty() ) m_abone_noid = atoi( str_tmp.c_str() );
+
// 最終更新チェック時間
GET_INFOVALUE( str_tmp, "checktime = " );
if( ! str_tmp.empty() ){
@@ -2034,6 +2124,7 @@ void ArticleBase::read_info()
<< "org_host = " << m_org_host << std::endl
<< "load = " << m_number_load << std::endl
<< "seen = " << m_number_seen << std::endl
+ << "max = " << m_number_max << std::endl
<< "modified = " << m_date_modified << std::endl
<< "writetime = " << m_write_time_date << std::endl
<< "writename = " << m_write_name << std::endl
@@ -2041,6 +2132,7 @@ void ArticleBase::read_info()
<< "writefixname = " << m_write_fixname << std::endl
<< "writefixmail = " << m_write_fixmail << std::endl
<< "status = " << m_status << std::endl
+ << "charcode = " << get_charcode() <<std::endl
<< "transparent_abone = " << m_abone_transparent << std::endl
<< "bookmarked_thread = " << m_bookmarked_thread << std::endl
;
@@ -2159,6 +2251,7 @@ void ArticleBase::save_info( const bool force )
<< "org_host = " << m_org_host << std::endl
<< "load = " << m_number_load << std::endl
<< "seen = " << m_number_seen << std::endl
+ << "max = " << m_number_max << std::endl
<< "modified = " << m_date_modified << std::endl
<< "access = " << get_access_time_str() << std::endl
<< "writetime = " << ss_write.str() << std::endl
@@ -2167,6 +2260,7 @@ void ArticleBase::save_info( const bool force )
<< "writefixname = " << m_write_fixname << std::endl
<< "writefixmail = " << m_write_fixmail << std::endl
<< "status = " << m_status << std::endl
+ << "charset = " << MISC::charcode_to_cstr( get_charcode() ) << std::endl
<< "aboneid = " << str_abone_id << std::endl
<< "abonename = " << str_abone_name << std::endl
<< "bookmark = " << ss_bookmark.str() << std::endl
@@ -2178,6 +2272,8 @@ void ArticleBase::save_info( const bool force )
<< "bkmark_thread = " << m_bookmarked_thread << std::endl
<< "posted = " << ss_posted.str() << std::endl
<< "aboneage = " << m_abone_age << std::endl
+ << "abonedefaultname = " << m_abone_default_name << std::endl
+ << "abonenoid = " << m_abone_noid << std::endl
<< "checktime = " << ss_check.str() << std::endl
<< "aboneboard = " << m_abone_board << std::endl
<< "aboneglobal = " << m_abone_global << std::endl
diff --git a/src/dbtree/articlebase.h b/src/dbtree/articlebase.h
index 2e327f2a..89930b16 100644
--- a/src/dbtree/articlebase.h
+++ b/src/dbtree/articlebase.h
@@ -9,10 +9,6 @@
#ifndef _ARTICLEBASE_H
#define _ARTICLEBASE_H
-#include "skeleton/lockable.h"
-
-#include "jdlib/constptr.h"
-
#include <ctime>
#include <list>
#include <string>
@@ -20,6 +16,12 @@
#include <unordered_set>
#include <vector>
+#include "skeleton/lockable.h"
+
+#include "jdlib/constptr.h"
+
+#include "charcode.h"
+
namespace DBTREE
{
class NodeTreeBase;
@@ -48,11 +50,14 @@ namespace DBTREE
std::string m_ext_err; // HTTPコード以外のエラーメッセージ
int m_status; // 状態 ( global.h で定義 )
+ CharCode m_charcode; // 文字エンコーディング
+
// 移転する前にこのスレがあった旧ホスト名( 移転していないなら m_url に含まれているホスト名と同じ )
// 詳しくはコンストラクタの説明を参照せよ
std::string m_org_host;
std::string m_subject; // サブジェクト
+ std::string m_modified_subject; // 置換で変更されたサブジェクト
int m_number; // サーバ上にあるレスの数
int m_number_diff; // レス増分( subject.txt をロードした時の m_number の増分 )
int m_number_new; // 新着数( ロードした時の差分読み込み数)
@@ -79,6 +84,8 @@ namespace DBTREE
bool m_abone_transparent; // 透明あぼーん
bool m_abone_chain; // 連鎖あぼーん
bool m_abone_age; // age ているレスをあぼーん
+ bool m_abone_default_name; // デフォルト名無しをあぼーん
+ bool m_abone_noid; // ID無しをあぼーん
bool m_abone_board; // 板レベルでのあぼーんを有効にする
bool m_abone_global; // 全体レベルでのあぼーんを有効にする
@@ -119,7 +126,7 @@ namespace DBTREE
public:
- ArticleBase( const std::string& datbase, const std::string& id, bool cached );
+ ArticleBase( const std::string& datbase, const std::string& id, bool cached, const CharCode charcode );
~ArticleBase();
bool empty();
@@ -142,13 +149,17 @@ namespace DBTREE
const std::string& get_id() const { return m_id; }
const std::string& get_key() const { return m_key; }
const std::string& get_subject() const { return m_subject; }
+ const std::string& get_modified_subject( const bool renew = false );
int get_number() const { return m_number; }
int get_number_diff() const { return m_number_diff; }
int get_number_new() const { return m_number_new; }
int get_number_load() const { return m_number_load; }
- int get_number_seen() const{ return m_number_seen; }
+ int get_number_seen() const { return m_number_seen; }
+ int get_number_max() const { return m_number_max; }
- void set_number_max( const int number ){ m_number_max = number; }
+ // 文字エンコーディング
+ CharCode get_charcode() const noexcept { return m_charcode; }
+ void set_charcode( const CharCode charcode ){ m_charcode = charcode; }
// スレ速度
int get_speed();
@@ -213,9 +224,6 @@ namespace DBTREE
// ref == true なら先頭に ">" を付ける
std::string get_res_str( int number, bool ref = false );
- // number 番のレスの生文字列を返す
- std::string get_raw_res_str( int number );
-
// 書き込み時の名前とメアド
const std::string& get_write_name() const { return m_write_name; }
void set_write_name( const std::string& str ){ m_save_info = true; m_write_name = str; }
@@ -291,6 +299,7 @@ namespace DBTREE
void set_number( const int number, const bool is_online );
void set_number_load( const int number_load );
void set_number_seen( const int number_seen );
+ void set_number_max( const int number_max );
void update_writetime();
// キャッシュ削除
@@ -329,6 +338,12 @@ namespace DBTREE
// ageあぼーん
bool get_abone_age() const { return m_abone_age; }
+ // デフォルト名無しあぼーん
+ bool get_abone_default_name() const { return m_abone_default_name; }
+
+ // ID無しあぼーん
+ bool get_abone_noid() const { return m_abone_noid; }
+
// 板レベルでのあぼーん
bool get_abone_board() const { return m_abone_board; }
@@ -348,6 +363,7 @@ namespace DBTREE
const std::list< std::string >& regexs,
const std::vector< char >& vec_abone_res,
const bool transparent, const bool chain, const bool age,
+ const bool default_name, const bool noid,
const bool board, const bool global
);
@@ -359,6 +375,8 @@ namespace DBTREE
void set_abone_transparent( const bool set ); // 透明
void set_abone_chain( const bool set ); // 連鎖
void set_abone_age( const bool set ); // age
+ void set_abone_default_name( const bool set ); // デフォルト名無し
+ void set_abone_noid( const bool set ); // ID無し
void set_abone_board( const bool set ); // 板レベルでのあぼーん
void set_abone_global( const bool set ); // 全体レベルでのあぼーん
@@ -380,7 +398,7 @@ namespace DBTREE
virtual void save_info( const bool force );
bool is_loading() const; // ロード中か
- bool is_checking_update(); // 更新チェック中か
+ bool is_checking_update() const; // 更新チェック中か
// スレッドのロード停止
void stop_load();
@@ -402,6 +420,9 @@ namespace DBTREE
// スレッド924か
bool is_924() const { return m_924; }
+ // NodeTree削除
+ void unlock_impl() override;
+
private:
// 更新チェック可能
@@ -417,7 +438,6 @@ namespace DBTREE
void slot_node_updated();
void slot_load_finished();
- void unlock_impl() override;
// お気に入りのアイコンとスレビューのタブのアイコンに更新マークを表示
// update == true の時に表示。falseなら戻す
diff --git a/src/dbtree/articlejbbs.cpp b/src/dbtree/articlejbbs.cpp
index 04589056..3bd97dc6 100644
--- a/src/dbtree/articlejbbs.cpp
+++ b/src/dbtree/articlejbbs.cpp
@@ -14,8 +14,8 @@
using namespace DBTREE;
-ArticleJBBS::ArticleJBBS( const std::string& datbase, const std::string& _id, bool cached )
- : ArticleBase( datbase, _id, cached )
+ArticleJBBS::ArticleJBBS( const std::string& datbase, const std::string& _id, bool cached, const CharCode charcode )
+ : ArticleBase( datbase, _id, cached, charcode )
{
assert( ! get_id().empty() );
@@ -27,18 +27,15 @@ ArticleJBBS::ArticleJBBS( const std::string& datbase, const std::string& _id, bo
}
-ArticleJBBS::~ArticleJBBS()
-{}
+ArticleJBBS::~ArticleJBBS() noexcept = default;
std::string ArticleJBBS::create_write_message( const std::string& name, const std::string& mail, const std::string& msg )
{
if( msg.empty() ) return std::string();
- std::string charset = DBTREE::board_charset( get_url() );
-
// DIR と BBS を分離する( ID = DIR/BBS )
- std::string boardid = DBTREE::board_id( get_url() );
+ const std::string& boardid = DBTREE::board_id( get_url() );
int i = boardid.find( "/" );
std::string dir = boardid.substr( 0, i );
std::string bbs = boardid.substr( i + 1 );
@@ -49,10 +46,10 @@ std::string ArticleJBBS::create_write_message( const std::string& name, const st
<< "&KEY=" << get_key()
<< "&DIR=" << dir
<< "&TIME=" << get_time_modified()
- << "&submit=" << MISC::charset_url_encode( "書き込む", charset )
- << "&NAME=" << MISC::charset_url_encode( name, charset )
- << "&MAIL=" << MISC::charset_url_encode( mail, charset )
- << "&MESSAGE=" << MISC::charset_url_encode( msg, charset );
+ << "&submit=" << MISC::url_encode( std::string( "書き込む" ), get_charcode() )
+ << "&NAME=" << MISC::url_encode( name, get_charcode() )
+ << "&MAIL=" << MISC::url_encode( mail, get_charcode() )
+ << "&MESSAGE=" << MISC::url_encode( msg, get_charcode() );
#ifdef _DEBUG
std::cout << "Articlejbbs::create_write_message " << ss_post.str() << std::endl;
diff --git a/src/dbtree/articlejbbs.h b/src/dbtree/articlejbbs.h
index e3a83d87..cb1caa19 100644
--- a/src/dbtree/articlejbbs.h
+++ b/src/dbtree/articlejbbs.h
@@ -17,8 +17,8 @@ namespace DBTREE
{
public:
- ArticleJBBS( const std::string& datbase, const std::string& id, bool cached );
- ~ArticleJBBS();
+ ArticleJBBS( const std::string& datbase, const std::string& id, bool cached, const CharCode charcode );
+ ~ArticleJBBS() noexcept;
// 書き込みメッセージ変換
std::string create_write_message( const std::string& name, const std::string& mail,
diff --git a/src/dbtree/articlelocal.cpp b/src/dbtree/articlelocal.cpp
index fcd0b088..53a0509c 100644
--- a/src/dbtree/articlelocal.cpp
+++ b/src/dbtree/articlelocal.cpp
@@ -10,8 +10,8 @@
using namespace DBTREE;
-ArticleLocal::ArticleLocal( const std::string& datbase, const std::string& id )
- : Article2chCompati( datbase, id, true )
+ArticleLocal::ArticleLocal( const std::string& datbase, const std::string& id, const CharCode charcode )
+ : Article2chCompati( datbase, id, true, charcode )
{
#ifdef _DEBUG
std::cout << "ArticleLocal::ArticleLocal datbase = " << datbase
diff --git a/src/dbtree/articlelocal.h b/src/dbtree/articlelocal.h
index 36e94412..cf5b0440 100644
--- a/src/dbtree/articlelocal.h
+++ b/src/dbtree/articlelocal.h
@@ -15,7 +15,7 @@ namespace DBTREE
{
public:
- ArticleLocal( const std::string& datbase, const std::string& id );
+ ArticleLocal( const std::string& datbase, const std::string& id, const CharCode charcode );
~ArticleLocal();
// ID がこのスレのものかどうか
diff --git a/src/dbtree/articlemachi.cpp b/src/dbtree/articlemachi.cpp
index 3ede4c4c..1ab666f3 100644
--- a/src/dbtree/articlemachi.cpp
+++ b/src/dbtree/articlemachi.cpp
@@ -17,8 +17,8 @@
using namespace DBTREE;
-ArticleMachi::ArticleMachi( const std::string& datbase, const std::string& _id, bool cached )
- : ArticleBase( datbase, _id, cached )
+ArticleMachi::ArticleMachi( const std::string& datbase, const std::string& _id, bool cached, const CharCode charcode )
+ : ArticleBase( datbase, _id, cached, charcode )
{
assert( !get_id().empty() );
@@ -30,25 +30,22 @@ ArticleMachi::ArticleMachi( const std::string& datbase, const std::string& _id,
}
-ArticleMachi::~ArticleMachi() noexcept
-{}
+ArticleMachi::~ArticleMachi() noexcept = default;
std::string ArticleMachi::create_write_message( const std::string& name, const std::string& mail, const std::string& msg )
{
if( msg.empty() ) return std::string();
- std::string charset = DBTREE::board_charset( get_url() );
-
std::stringstream ss_post;
ss_post.clear();
ss_post << "BBS=" << DBTREE::board_id( get_url() )
<< "&KEY=" << get_key()
<< "&TIME=" << get_time_modified()
- << "&submit=" << MISC::charset_url_encode( "書き込む", charset )
- << "&NAME=" << MISC::charset_url_encode( name, charset )
- << "&MAIL=" << MISC::charset_url_encode( mail, charset )
- << "&MESSAGE=" << MISC::charset_url_encode( msg, charset );
+ << "&submit=" << MISC::url_encode( std::string( "書き込む" ), get_charcode() )
+ << "&NAME=" << MISC::url_encode( name, get_charcode() )
+ << "&MAIL=" << MISC::url_encode( mail, get_charcode() )
+ << "&MESSAGE=" << MISC::url_encode( msg, get_charcode() );
#ifdef _DEBUG
std::cout << "ArticleMachi::create_write_message " << ss_post.str() << std::endl;
diff --git a/src/dbtree/articlemachi.h b/src/dbtree/articlemachi.h
index 3383f251..a8cf78bf 100644
--- a/src/dbtree/articlemachi.h
+++ b/src/dbtree/articlemachi.h
@@ -17,7 +17,7 @@ namespace DBTREE
{
public:
- ArticleMachi( const std::string& datbase, const std::string& id, bool cached );
+ ArticleMachi( const std::string& datbase, const std::string& id, bool cached, const CharCode charcode );
~ArticleMachi() noexcept;
// 書き込みメッセージ変換
diff --git a/src/dbtree/board2ch.cpp b/src/dbtree/board2ch.cpp
index 1b692581..9ab0a2b6 100644
--- a/src/dbtree/board2ch.cpp
+++ b/src/dbtree/board2ch.cpp
@@ -31,8 +31,7 @@ Board2ch::Board2ch( const std::string& root, const std::string& path_board, cons
}
-Board2ch::~Board2ch() noexcept
-{}
+Board2ch::~Board2ch() noexcept = default;
// ユーザエージェント
@@ -180,7 +179,7 @@ std::string Board2ch::create_newarticle_message( const std::string& subject, con
std::stringstream ss_post;
ss_post.clear();
ss_post << "bbs=" << get_id()
- << "&subject=" << MISC::charset_url_encode( subject, get_charset() );
+ << "&subject=" << MISC::url_encode( subject, get_charcode() );
// キーワード( hana=mogera や suka=pontan など )
const std::string keyword = get_keyword_for_write();
@@ -194,14 +193,14 @@ std::string Board2ch::create_newarticle_message( const std::string& subject, con
}
ss_post << "&time=" << get_time_modified()
- << "&submit=" << MISC::charset_url_encode( "新規スレッド作成", get_charset() )
- << "&FROM=" << MISC::charset_url_encode( name, get_charset() )
- << "&mail=" << MISC::charset_url_encode( mail, get_charset() )
- << "&MESSAGE=" << MISC::charset_url_encode( msg, get_charset() );
+ << "&submit=" << MISC::url_encode( std::string( "新規スレッド作成" ), get_charcode() )
+ << "&FROM=" << MISC::url_encode( name, get_charcode() )
+ << "&mail=" << MISC::url_encode( mail, get_charcode() )
+ << "&MESSAGE=" << MISC::url_encode( msg, get_charcode() );
if( CORE::get_loginp2()->login_now() ){
- ss_post << "&detect_hint=" << MISC::charset_url_encode( "◎◇", get_charset() )
+ ss_post << "&detect_hint=" << MISC::url_encode( std::string( "◎◇" ), get_charcode() )
<< "&host=" << MISC::url_encode( MISC::get_hostname( get_root(), false ) )
<< "&key="
<< "&popup=1"
@@ -256,12 +255,9 @@ ArticleBase* Board2ch::append_article( const std::string& datbase, const std::st
{
if( empty() ) return get_article_null();
- ArticleBase* article = new DBTREE::Article2ch( datbase, id, cached );
+ ArticleBase* article = new DBTREE::Article2ch( datbase, id, cached, get_charcode() );
if( article ){
get_hash_article()->push( article );
-
- // 最大レス数セット
- article->set_number_max( get_number_max_res() );
}
else return get_article_null();
diff --git a/src/dbtree/board2chcompati.cpp b/src/dbtree/board2chcompati.cpp
index e5179d22..4dc62893 100644
--- a/src/dbtree/board2chcompati.cpp
+++ b/src/dbtree/board2chcompati.cpp
@@ -9,6 +9,7 @@
#include "settingloader.h"
#include "ruleloader.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/miscmsg.h"
#include "jdlib/jdregex.h"
@@ -47,7 +48,7 @@ Board2chCompati::Board2chCompati( const std::string& root, const std::string& pa
set_subjecttxt( "subject.txt" );
set_ext( ".dat" );
set_id( path_board.substr( 1 ) ); // 先頭の '/' を除く
- set_charset( "MS932" );
+ set_charcode( CHARCODE_SJIS );
BoardBase::set_basicauth( basicauth );
}
@@ -75,8 +76,10 @@ Board2chCompati::~Board2chCompati()
//
bool Board2chCompati::is_valid( const std::string& filename )
{
- if( filename.find( get_ext() ) == std::string::npos ) return false;
- if( filename.length() - filename.rfind( get_ext() ) != get_ext().length() ) return false;
+ size_t lng_filename = filename.length();
+ size_t lng_ext = get_ext().length();
+ if( lng_ext != 0 && ( lng_filename <= lng_ext ||
+ filename.compare( lng_filename - lng_ext, lng_ext, get_ext() ) ) ) return false;
size_t dig, n;
MISC::str_to_uint( filename.c_str(), dig, n );
@@ -97,90 +100,27 @@ std::string Board2chCompati::cookie_for_write()
std::cout << "Board2chCompati::cookie_for_write\n";
#endif
- JDLIB::Regex regex;
- const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
-
- std::string cookie_expire;
- std::string cookie_path;
- std::string cookie_pon;
std::string cookie_hap = get_hap();
- std::string cookie_name;
- std::string cookie_mail;
-
- const std::string query_expire = "expires=([^;]*)";
- const std::string query_path = "path=([^;]*)";
- const std::string query_pon = "PON=([^;]*)?";
- const std::string query_hap = "HAP=([^;]*)?";
- const std::string query_name = "NAME=([^;]*)?";
- const std::string query_mail = "MAIL=([^;]*)?";
-
- bool use_pon = false;
- bool use_hap = ! cookie_hap.empty();
- bool use_name = false;
- bool use_mail = false;
-
+ std::string cookie;
std::list< std::string >::const_iterator it = list_cookies.begin();
- // expire と path は一つ目のcookieから取得
- if( regex.exec( query_expire, (*it), offset, icase, newline, usemigemo, wchar ) ) cookie_expire = regex.str( 1 );
- if( regex.exec( query_path, (*it), offset, icase, newline, usemigemo, wchar ) ) cookie_path = regex.str( 1 );
-
for( ; it != list_cookies.end(); ++it ){
+ const std::string tmp_cookie = MISC::Iconv( (*it), get_charcode(), CHARCODE_UTF8 );
- const std::string tmp_cookie = MISC::Iconv( (*it), get_charset(), "UTF-8" );
+ if( ! cookie_hap.empty() && tmp_cookie.compare( 0, 4, "HAP=" ) == 0 ) continue;
-#ifdef _DEBUG
- std::cout << tmp_cookie << std::endl;
-#endif
-
- if( regex.exec( query_pon, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){
- use_pon = true;
- cookie_pon = regex.str( 1 );
- }
- if( ! use_hap && regex.exec( query_hap, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){
- use_hap = true;
- cookie_hap = regex.str( 1 );
- }
- if( regex.exec( query_name, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){
- use_name = true;
- cookie_name = MISC::charset_url_encode( regex.str( 1 ), get_charset() );
- }
- if( regex.exec( query_mail, tmp_cookie, offset, icase, newline, usemigemo, wchar ) ){
- use_mail = true;
- cookie_mail = MISC::charset_url_encode( regex.str( 1 ), get_charset() );
- }
+ if( ! cookie.empty() ) cookie += "; ";
+ if( tmp_cookie.find_first_of( ';' ) == std::string::npos )
+ cookie += tmp_cookie;
+ else
+ cookie += tmp_cookie.substr( 0, tmp_cookie.find_first_of( ';' ) );
}
- // PONを取得していないときはHAPを送らない
- if( ! use_pon || cookie_pon.empty() ){
- use_hap = false;
- cookie_hap = std::string();
+ if( ! cookie_hap.empty() ){
+ if( ! cookie.empty() ) cookie += "; ";
+ cookie += "HAP=" + cookie_hap;
}
-#ifdef _DEBUG
- std::cout << "expire = " << cookie_expire << std::endl
- << "path = " << cookie_path << std::endl
- << "pon = " << cookie_pon << " " << use_pon << std::endl
- << "hap = " << cookie_hap << " " << use_hap << std::endl
- << "name = " << cookie_name << " " << use_name << std::endl
- << "mail = " << cookie_mail << " " << use_mail << std::endl;
-#endif
-
- std::string cookie;
-
- if( use_pon ) cookie += "PON=" + cookie_pon + "; ";
- if( use_hap ) cookie += "HAP=" + cookie_hap + "; ";
- if( use_name ) cookie += "NAME=" + cookie_name + "; ";
- if( use_mail ) cookie += "MAIL=" + cookie_mail + "; ";
-
- if( cookie.empty() ) return std::string();
-
- cookie += "expires=" + cookie_expire + "; path=" + cookie_path;
-
#ifdef _DEBUG
std::cout << "cookie = " << cookie << std::endl;
#endif
@@ -240,7 +180,7 @@ void Board2chCompati::analyze_keyword_for_write( const std::string& html )
// キーワード取得
if( ! keyword.empty() ) keyword += "&";
- keyword += MISC::charset_url_encode( name, get_charset() ) + "=" + MISC::charset_url_encode( value, get_charset() );
+ keyword += MISC::url_encode( name, get_charcode() ) + "=" + MISC::url_encode( value, get_charcode() );
}
#ifdef _DEBUG
@@ -261,12 +201,12 @@ std::string Board2chCompati::create_newarticle_message( const std::string& subje
std::stringstream ss_post;
ss_post.clear();
ss_post << "bbs=" << get_id()
- << "&subject=" << MISC::charset_url_encode( subject, get_charset() )
+ << "&subject=" << MISC::url_encode( subject, get_charcode() )
<< "&time=" << get_time_modified()
- << "&submit=" << MISC::charset_url_encode( "新規スレッド作成", get_charset() )
- << "&FROM=" << MISC::charset_url_encode( name, get_charset() )
- << "&mail=" << MISC::charset_url_encode( mail, get_charset() )
- << "&MESSAGE=" << MISC::charset_url_encode( msg, get_charset() );
+ << "&submit=" << MISC::url_encode( std::string( "新規スレッド作成" ), get_charcode() )
+ << "&FROM=" << MISC::url_encode( name, get_charcode() )
+ << "&mail=" << MISC::url_encode( mail, get_charcode() )
+ << "&MESSAGE=" << MISC::url_encode( msg, get_charcode() );
#ifdef _DEBUG
std::cout << "Board2chCompati::create_newarticle_message " << ss_post.str() << std::endl;
@@ -312,12 +252,9 @@ ArticleBase* Board2chCompati::append_article( const std::string& datbase, const
{
if( empty() ) return get_article_null();
- ArticleBase* article = new DBTREE::Article2chCompati( datbase, id, cached );
+ ArticleBase* article = new DBTREE::Article2chCompati( datbase, id, cached, get_charcode() );
if( article ){
get_hash_article()->push( article );
-
- // 最大レス数セット
- article->set_number_max( get_number_max_res() );
}
else return get_article_null();
@@ -366,13 +303,9 @@ void Board2chCompati::parse_subject( const char* str_subject_txt )
}
// subject取得
- bool exist_amp = false;
++pos;
str_subject = pos;
- while( *pos != '\0' && *pos != '\n' ){
- if( *pos == '&' ) exist_amp = true;
- ++pos;
- }
+ while( *pos != '\0' && *pos != '\n' ) ++pos;
--pos;
while( *pos != '(' && *pos != '\n' && pos != str_subject ) --pos;
@@ -404,16 +337,8 @@ void Board2chCompati::parse_subject( const char* str_subject_txt )
artinfo.id.assign( str_id_dat, lng_id_dat );
- if( str_subject[ lng_subject-1 ] == ' ' ){
- lng_subject--; // 2chのsubject.txtは()の前に空白が一つ入る
- }
artinfo.subject.assign( str_subject, lng_subject );
- if( exist_amp ){
- artinfo.subject = MISC::replace_str( artinfo.subject, "&lt;", "<" );
- artinfo.subject = MISC::replace_str( artinfo.subject, "&gt;", ">" );
- }
-
const auto num = std::atoi( str_num );
artinfo.number = ( num < CONFIG::get_max_resnumber() ) ? num : CONFIG::get_max_resnumber();
@@ -497,6 +422,18 @@ std::string Board2chCompati::localrule()
}
+//
+// SETTING.TXTのURL
+//
+// (例) "http://www.hoge2ch.net/hogeboard/SETTING.TXT"
+//
+//
+std::string Board2chCompati::url_settingtxt()
+{
+ return url_boardbase() + SETTING_TXT;
+}
+
+
std::string Board2chCompati::settingtxt()
{
if( m_settingloader ){
@@ -560,10 +497,10 @@ void Board2chCompati::load_rule_setting()
#endif
if( ! m_ruleloader ) m_ruleloader = new RuleLoader( url_boardbase() );
- m_ruleloader->load_text();
+ m_ruleloader->load_text( get_charcode() );
if( ! m_settingloader ) m_settingloader = new SettingLoader( url_boardbase() );
- m_settingloader->load_text();
+ m_settingloader->load_text( get_charcode() );
}
@@ -579,17 +516,25 @@ void Board2chCompati::download_rule_setting()
#endif
if( ! m_ruleloader ) m_ruleloader = new RuleLoader( url_boardbase() );
- m_ruleloader->download_text();
+ m_ruleloader->download_text( get_charcode() );
if( ! m_settingloader ) m_settingloader = new SettingLoader( url_boardbase() );
- m_settingloader->download_text();
+ m_settingloader->download_text( get_charcode() );
}
//
-// レス数であぼーん(グローバル)
+// レス数(最小)であぼーん(グローバル)
//
-int Board2chCompati::get_abone_number_global()
+int Board2chCompati::get_abone_min_number_global()
{
- return CONFIG::get_abone_number_thread();
+ return CONFIG::get_abone_min_number_thread();
+}
+
+//
+// レス数(最大)であぼーん(グローバル)
+//
+int Board2chCompati::get_abone_max_number_global()
+{
+ return CONFIG::get_abone_max_number_thread();
}
diff --git a/src/dbtree/board2chcompati.h b/src/dbtree/board2chcompati.h
index f056092c..0c85dba2 100644
--- a/src/dbtree/board2chcompati.h
+++ b/src/dbtree/board2chcompati.h
@@ -44,6 +44,8 @@ namespace DBTREE
// ローカルルール
std::string localrule() override;
+ // SETTING.TXT のURL
+ std::string url_settingtxt() override;
// SETTING.TXT
std::string settingtxt() override;
std::string default_noname() override;
@@ -63,7 +65,8 @@ namespace DBTREE
void download_rule_setting() override;
// レス数であぼーん(グローバル)
- int get_abone_number_global() override;
+ int get_abone_min_number_global() override;
+ int get_abone_max_number_global() override;
};
}
diff --git a/src/dbtree/boardbase.cpp b/src/dbtree/boardbase.cpp
index e050b17b..e29cf2b9 100644
--- a/src/dbtree/boardbase.cpp
+++ b/src/dbtree/boardbase.cpp
@@ -13,6 +13,7 @@
#include "jdlib/jdiconv.h"
#include "jdlib/jdregex.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/miscmsg.h"
#include "jdlib/loaderdata.h"
@@ -39,7 +40,7 @@ int cache_nohit_art = 0;
enum
{
- SIZE_OF_RAWDATA = 2 * 1024 * 1024
+ SIZE_OF_RAWDATA = 256 * 1024
};
using namespace DBTREE;
@@ -62,7 +63,7 @@ BoardBase::BoardBase( const std::string& root, const std::string& path_board, co
, m_number_max_res( 0 )
, m_iconv( NULL )
, m_rawdata( NULL )
- , m_rawdata_left( NULL )
+ , m_charcode_bak( CHARCODE_UNKNOWN )
, m_read_info( 0 )
, m_append_articles( false )
, m_get_article( NULL )
@@ -112,7 +113,7 @@ BoardBase::~BoardBase()
ArticleBase* BoardBase::get_article_null()
{
- if( ! m_article_null ) m_article_null = new DBTREE::ArticleBase( "", "", false );
+ if( ! m_article_null ) m_article_null = new DBTREE::ArticleBase( "", "", false, get_charcode() );
return m_article_null;
}
@@ -128,8 +129,8 @@ bool BoardBase::empty()
//
bool BoardBase::equal( const std::string& url )
{
- if( url.find( get_root() ) == 0
- && url.find( get_path_board() + "/" ) != std::string::npos ) return true;
+ if( url.compare( 0, get_root().length(), get_root() ) == 0
+ && url.find( get_path_board() + "/", get_root().length() ) != std::string::npos ) return true;
return false;
}
@@ -302,7 +303,7 @@ void BoardBase::set_list_cookies_for_write( const std::list< std::string >& list
#endif
std::string key;
- const size_t n = cookie.find( "=" );
+ const size_t n = cookie.find_first_of( '=' );
if( n != std::string::npos ) key = cookie.substr( 0, n+1 );
// 更新
@@ -343,9 +344,6 @@ void BoardBase::clear()
if( m_rawdata ) free( m_rawdata );
m_rawdata = NULL;
- if( m_rawdata_left ) free( m_rawdata_left );
- m_rawdata_left = NULL;
-
m_lng_rawdata = 0;
m_lng_rawdata_left = 0;
@@ -372,7 +370,7 @@ void BoardBase::send_update_board()
// "update_board" コマンドの後に"update_board_item"を送ると
// ローディングが終了しているため行を二回更新してしまうので注意
// 詳しくは BoardViewBase::update_item() を参照
- CORE::core_set_command( "update_board_item", url_subject(),
+ CORE::core_set_command( "update_board_item", url_boardbase(),
std::string() // IDとして空文字を送る
);
@@ -495,9 +493,6 @@ void BoardBase::set_number_max_res( const int number )
#endif
m_number_max_res = MAX( 0, MIN( CONFIG::get_max_resnumber(), number ) );
-
- ArticleHashIterator it = m_hash_article->begin();
- for( ; it != m_hash_article->end(); ++it ) ( *it )->set_number_max( m_number_max_res );
}
@@ -544,9 +539,9 @@ void BoardBase::update_url( const std::string& root, const std::string& path_boa
m_root = root;
m_path_board = path_board;
- m_query_dat = std::string();
- m_query_cgi = std::string();
- m_query_kako = std::string();
+ m_query_dat.clear();
+ m_query_cgi.clear();
+ m_query_kako.clear();
// modified 時刻をリセット
// 自動移転処理後に bbsmenu.html を読み込んだときに、bbsmenu.html の
@@ -576,10 +571,6 @@ std::string BoardBase::url_dat( const std::string& url, int& num_from, int& num_
JDLIB::Regex regex;
const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
std::string id; // スレッドのID
@@ -589,30 +580,38 @@ std::string BoardBase::url_dat( const std::string& url, int& num_from, int& num_
num_from = num_to = 0;
- if( m_query_dat.empty() ){
+ if( ! m_query_dat.compiled() ){
+
+ const bool icase = false;
+ const bool newline = true;
+ const bool usemigemo = false;
+ const bool wchar = false;
// dat 型
const std::string datpath = MISC::replace_str( url_datpath(), "?", "\\?" );
- m_query_dat = "^ *(https?://.+" + datpath + ")([1234567890]+" + get_ext() + ") *$";
+ const std::string reg_dat = "^ *(https?://.+" + datpath + ")([0-9]+" + get_ext() + ") *$";
+ m_query_dat.set( reg_dat, icase, newline, usemigemo, wchar );
// read.cgi型
const std::string cgipath = MISC::replace_str( url_readcgipath(), "?", "\\?" );
- m_query_cgi = "^ *(https?://.+" + cgipath + ")([1234567890]+)/?r?(l50)?([1234567890]+)?(-)?([1234567890]+)?.*$";
+ const std::string reg_cgi = "^ *(https?://.+" + cgipath + ")([0-9]+)/?r?(l50)?([0-9]+)?(-)?([0-9]+)?.*$";
+ m_query_cgi.set( reg_cgi, icase, newline, usemigemo, wchar );
// 過去ログかどうか
const std::string pathboard = MISC::replace_str( m_path_board, "?", "\\?" );
- m_query_kako = "^ *(https?://.+)" + pathboard + "/kako(/[1234567890]+)?/[1234567890]+/([1234567890]+).html *$";
+ const std::string reg_kako = "^ *(https?://.+)" + pathboard + "/kako(/[0-9]+)?/[0-9]+/([0-9]+).html *$";
+ m_query_kako.set( reg_kako, icase, newline, usemigemo, wchar );
#ifdef _DEBUG
- std::cout << "query_dat = " << m_query_dat << std::endl;
- std::cout << "query_cgi = " << m_query_cgi << std::endl;
- std::cout << "query_kako = " << m_query_kako << std::endl;
+ std::cout << "reg_dat = " << reg_dat << std::endl;
+ std::cout << "reg_cgi = " << reg_cgi << std::endl;
+ std::cout << "reg_kako = " << reg_kako << std::endl;
#endif
}
- if( regex.exec( m_query_dat , url, offset, icase, newline, usemigemo, wchar ) ) id = regex.str( 2 );
+ if( regex.match( m_query_dat, url, offset ) ) id = regex.str( 2 );
- else if( regex.exec( m_query_cgi , url, offset, icase, newline, usemigemo, wchar ) ){
+ else if( regex.match( m_query_cgi, url, offset ) ){
id = regex.str( 2 ) + get_ext();
@@ -644,10 +643,7 @@ std::string BoardBase::url_dat( const std::string& url, int& num_from, int& num_
// どちらでもない(スレのURLでない)場合
else{
-#ifdef _DEBUG
- std::cout << "query_kako = " << m_query_kako << std::endl;
-#endif
- if( regex.exec( m_query_kako , url, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.match( m_query_kako, url, offset ) ){
std::string url_tmp = regex.str( 1 ) + url_datpath() + regex.str( 3 ) + get_ext();
#ifdef _DEBUG
@@ -994,7 +990,7 @@ ArticleBase* BoardBase::get_article_fromURL( const std::string& url )
void BoardBase::download_subject( const std::string& url_update_view, const bool read_from_cache )
{
#ifdef _DEBUG
- std::cout << "BoardBase::download_subject " << url_subject() << std::endl
+ std::cout << "BoardBase::download_subject " << url_boardbase() << std::endl
<< "url_update_view = " << url_update_view << std::endl
<< "read_from_cache = " << read_from_cache << std::endl
<< "empty = " << empty() << std::endl
@@ -1019,6 +1015,9 @@ void BoardBase::download_subject( const std::string& url_update_view, const bool
m_is_booting = SESSION::is_booting();
+ // charcodeを一時保存
+ m_charcode_bak = get_charcode();
+
// オフライン
if( ! m_is_online ){
@@ -1079,6 +1078,8 @@ void BoardBase::receive_data( const char* data, size_t size )
if( ! m_rawdata ) m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA );
+ // XXX バッファから溢れる分は捨てる
+ if( size >= ( SIZE_OF_RAWDATA - m_lng_rawdata ) ) size = SIZE_OF_RAWDATA - m_lng_rawdata - 1;
memcpy( m_rawdata + m_lng_rawdata , data, size );
m_lng_rawdata += size;
m_rawdata[ m_lng_rawdata ] = '\0';
@@ -1090,24 +1091,21 @@ void BoardBase::receive_data( const char* data, size_t size )
// 改行ごとに区切ってUTF8に文字コード変換して解析
//
- if( ! m_rawdata_left ) m_rawdata_left = ( char* )malloc( SIZE_OF_RAWDATA );
- if( ! m_iconv ) m_iconv = new JDLIB::Iconv( m_charset, "UTF-8" );
+ if( get_code() != HTTP_OK ) set_charcode( m_charcode_bak );
+ if( ! m_iconv ) m_iconv = new JDLIB::Iconv( get_charcode(), CHARCODE_UTF8 );
- memcpy( m_rawdata_left + m_lng_rawdata_left, data, size );
-
- size_t byte_in = size + m_lng_rawdata_left;
- m_lng_rawdata_left = byte_in;
- while( byte_in && m_rawdata_left[ byte_in -1 ] != '\n' ) --byte_in;
+ size_t byte_in = m_lng_rawdata - m_lng_rawdata_left;
+ const char* pos_left = m_rawdata + m_lng_rawdata_left;
+ while( byte_in && *( pos_left + byte_in - 1 ) != '\n' ) --byte_in;
if( byte_in ){
int byte_out;
- const char* rawdata_utf8 = m_iconv->convert( m_rawdata_left, byte_in, byte_out );
+ const char* subjects = m_iconv->convert( pos_left, byte_in, byte_out );
- parse_subject( rawdata_utf8 );
+ parse_subject( subjects );
- // 残りを先頭に移動
- m_lng_rawdata_left -= byte_in;
- memmove( m_rawdata_left, m_rawdata_left + byte_in, m_lng_rawdata_left );
+ // 残りの先頭を更新
+ m_lng_rawdata_left += byte_in;
#ifdef _DEBUG
std::cout << "BoardBase::receive_data lng_rawdata = " << m_lng_rawdata << " size = " << size
@@ -1149,7 +1147,7 @@ void BoardBase::receive_finish()
set_date_modified( std::string() );
send_update_board();
- if( m_lng_rawdata && get_code() == HTTP_OK && std::string( m_rawdata ).find( "window.location.href" ) != std::string::npos ){
+ if( m_lng_rawdata && get_code() == HTTP_OK && strstr( m_rawdata, "window.location.href" ) != NULL ){
#ifdef _DEBUG
std::cout << m_rawdata << std::endl;
@@ -1164,7 +1162,13 @@ void BoardBase::receive_finish()
std::string query = ".*window.location.href=\"([^\"]*)\".*";
if( regex.exec( query, m_rawdata, offset, icase, newline, usemigemo, wchar ) ){
- const std::string new_url = regex.str( 1 );
+ std::string new_url = regex.str( 1 );
+ if( new_url.compare( 0, 2, "//" ) == 0 ){
+ std::string tmp_url = url_boardbase();
+ size_t pos = tmp_url.find("://");
+ if( pos != std::string::npos )
+ new_url.insert( 0, tmp_url.substr( 0, pos + 1 ) );
+ }
int ret = Gtk::RESPONSE_YES;
if( CONFIG::get_show_movediag() ){
@@ -1187,7 +1191,7 @@ void BoardBase::receive_finish()
// 再読み込み
const std::string str_tab = "false";
- CORE::core_set_command( "open_board", url_subject(), str_tab );
+ CORE::core_set_command( "open_board", url_boardbase(), str_tab );
}
}
}
@@ -1280,17 +1284,20 @@ void BoardBase::receive_finish()
// 一度全てのarticleをdat落ち状態にして subject.txt に
// 含まれているものだけ regist_article()の中で通常状態にする
- if( m_is_online
- || m_is_booting // ブート中の時も状態を変えないと起動直後にスレ一覧を復元した時にdat落ちしたスレが表示されない
- ){
+ ArticleHashIterator hash_it = m_hash_article->begin();
+ for( ; hash_it != m_hash_article->end(); ++hash_it ){
- ArticleHashIterator it = m_hash_article->begin();
- for( ; it != m_hash_article->end(); ++it ){
-
- int status = ( *it )->get_status();
+ if( read_from_cache && ! ( *hash_it )->is_924()
+ && ( *hash_it )->get_since_time() > m_last_access_time ){
+ // キャッシュから読み込む場合にsubject.txtよりも新しいスレは残す
+ ( *hash_it )->read_info();
+ if( ! is_abone_thread( *hash_it ) ) m_list_subject.push_back( *hash_it );
+ }
+ else{
+ int status = ( *hash_it )->get_status();
status &= ~STATUS_NORMAL;
status |= STATUS_OLD;
- ( *it )->set_status( status );
+ ( *hash_it )->set_status( status );
}
}
@@ -1524,7 +1531,8 @@ bool BoardBase::is_abone_thread( ArticleBase* article )
if( ! article ) return false;
if( article->empty() ) return false;
- const int check_number = article->get_number_load() ? 0: ( m_abone_number_thread ? m_abone_number_thread : get_abone_number_global() );
+ const int check_min_number = article->get_number_load() ? 0: ( m_abone_min_number_thread ? m_abone_min_number_thread : get_abone_min_number_global() );
+ const int check_max_number = article->get_number_load() ? 0: ( m_abone_max_number_thread ? m_abone_max_number_thread : get_abone_max_number_global() );
const int check_hour = article->get_number_load() ? 0: ( m_abone_hour_thread ? m_abone_hour_thread : CONFIG::get_abone_hour_thread() );
const bool check_thread = ! m_list_abone_thread.empty();
const bool check_word = ! m_list_abone_word_thread.empty();
@@ -1532,7 +1540,7 @@ bool BoardBase::is_abone_thread( ArticleBase* article )
const bool check_word_global = ! CONFIG::get_list_abone_word_thread().empty();
const bool check_regex_global = ! CONFIG::get_list_abone_regex_thread().empty();
- if( !check_number && !check_hour && !check_thread && !check_word && !check_regex && !check_word_global && !check_regex_global ) return false;
+ if( !check_min_number && !check_max_number && !check_hour && !check_thread && !check_word && !check_regex && !check_word_global && !check_regex_global ) return false;
JDLIB::Regex regex;
const size_t offset = 0;
@@ -1542,7 +1550,8 @@ bool BoardBase::is_abone_thread( ArticleBase* article )
const bool wchar = CONFIG::get_abone_wchar();
// レスの数であぼーん
- if( check_number ) if( article->get_number() >= check_number ) return true;
+ if( check_min_number ) if( article->get_number() <= check_min_number ) return true;
+ if( check_max_number ) if( article->get_number() >= check_max_number ) return true;
// スレ立てからの時間であぼーん
if( check_hour ) if( article->get_hour() >= check_hour ) return true;
@@ -1551,7 +1560,7 @@ bool BoardBase::is_abone_thread( ArticleBase* article )
if( check_thread ){
std::list< std::string >::iterator it = m_list_abone_thread.begin();
for( ; it != m_list_abone_thread.end(); ++it ){
- if( MISC::remove_space( article->get_subject() ) == MISC::remove_space(*it) ){
+ if( article->get_subject() == *it ){
// 対象スレがDat落ちした場合はあぼーんしなかったスレ名をリストから消去する
// remove_old_abone_thread() も参照
@@ -1676,7 +1685,7 @@ void BoardBase::update_abone_thread( const bool redraw )
const bool online = SESSION::is_online();
SESSION::set_online( false );
- download_subject( ( redraw ? url_subject() : std::string() ), false );
+ download_subject( ( redraw ? url_boardbase() : std::string() ), false );
SESSION::set_online( online );
}
@@ -1757,7 +1766,8 @@ void BoardBase::add_abone_word_board( const std::string& word )
void BoardBase::reset_abone_thread( const std::list< std::string >& threads,
const std::list< std::string >& words,
const std::list< std::string >& regexs,
- const int number,
+ const int min_number,
+ const int max_number,
const int hour,
const bool redraw
)
@@ -1779,7 +1789,8 @@ void BoardBase::reset_abone_thread( const std::list< std::string >& threads,
m_list_abone_regex_thread = MISC::remove_space_from_list( regexs );
m_list_abone_regex_thread = MISC::remove_nullline_from_list( m_list_abone_regex_thread );
- m_abone_number_thread = number;
+ m_abone_min_number_thread = min_number;
+ m_abone_max_number_thread = max_number;
m_abone_hour_thread = hour;
update_abone_thread( redraw );
@@ -1851,7 +1862,7 @@ void BoardBase::search_cache( std::vector< DBTREE::ArticleBase* >& list_article,
)
{
#ifdef _DEBUG
- std::cout << "BoardBase::search_cache " << url_subject() << std::endl;
+ std::cout << "BoardBase::search_cache " << url_boardbase() << std::endl;
#endif
if( empty() ) return;
@@ -1861,7 +1872,7 @@ void BoardBase::search_cache( std::vector< DBTREE::ArticleBase* >& list_article,
if( m_hash_article->size() == 0 ) return;
const bool append_all = query.empty();
- const std::string query_local = MISC::Iconv( query, "UTF-8", get_charset() );
+ const std::string query_local = MISC::Iconv( query, CHARCODE_UTF8, get_charcode() );
const std::list< std::string > list_query = MISC::split_line( query_local );
const std::string path_board_root = CACHE::path_board_root_fast( url_boardbase() );
@@ -2005,6 +2016,9 @@ void BoardBase::read_board_info()
m_show_oldlog = cf.get_option_bool( "show_oldlog", false );
+ std::string charset = cf.get_option_str( "charset", MISC::charcode_to_cstr( get_charcode() ) );
+ set_charcode( MISC::charcode_from_cstr( charset.c_str() ) );
+
std::string str_tmp;
// あぼーん id は再起動ごとにリセット
@@ -2036,7 +2050,8 @@ void BoardBase::read_board_info()
if( ! str_tmp.empty() ) m_list_abone_regex_thread = MISC::strtolist( str_tmp );
// レス数であぼーん
- m_abone_number_thread = cf.get_option_int( "abonenumberthread", 0, 0, 9999 );
+ m_abone_min_number_thread = cf.get_option_int( "aboneminnumberthread", 0, 0, CONFIG::get_max_resnumber() );
+ m_abone_max_number_thread = cf.get_option_int( "abonenumberthread", 0, 0, CONFIG::get_max_resnumber() );
// スレ立てからの経過時間であぼーん
m_abone_hour_thread = cf.get_option_int( "abonehourthread", 0, 0, 9999 );
@@ -2153,6 +2168,7 @@ void BoardBase::save_jdboard_info()
<< "view_sort_pre_mode = " << m_view_sort_pre_mode << std::endl
<< "check_noname = " << m_check_noname << std::endl
<< "show_oldlog = " << m_show_oldlog << std::endl
+ << "charset = " << MISC::charcode_to_cstr( get_charcode() ) << std::endl
// IDは再起動ごとにリセット
// << "aboneid = " << str_abone_id << std::endl
@@ -2163,7 +2179,8 @@ void BoardBase::save_jdboard_info()
<< "abonethread = " << str_abone_thread << std::endl
<< "abonewordthread = " << str_abone_word_thread << std::endl
<< "aboneregexthread = " << str_abone_regex_thread << std::endl
- << "abonenumberthread = " << m_abone_number_thread << std::endl
+ << "aboneminnumberthread = " << m_abone_min_number_thread << std::endl
+ << "abonenumberthread = " << m_abone_max_number_thread << std::endl
<< "abonehourthread = " << m_abone_hour_thread << std::endl
<< "mode_local_proxy = " << m_mode_local_proxy << std::endl
@@ -2311,7 +2328,7 @@ void BoardBase::show_updateicon( const bool update )
m_status |= STATUS_UPDATE;
// スレ一覧のタブのアイコン表示を更新
- CORE::core_set_command( "toggle_board_icon", url_subject() );
+ CORE::core_set_command( "toggle_board_icon", url_boardbase() );
// サイドバーのアイコン表示を更新
CORE::core_set_command( "toggle_sidebar_boardicon", url_datbase() );
@@ -2331,7 +2348,7 @@ void BoardBase::show_updateicon( const bool update )
// サイドバーのアイコン表示を戻す
// スレ一覧のタブのアイコンはBoardViewがロード終了時に自動的に戻す
- CORE::core_set_command( "toggle_sidebar_boardicon", url_subject() );
+ CORE::core_set_command( "toggle_sidebar_boardicon", url_boardbase() );
save_info();
}
diff --git a/src/dbtree/boardbase.h b/src/dbtree/boardbase.h
index d56a9364..7b18d20b 100644
--- a/src/dbtree/boardbase.h
+++ b/src/dbtree/boardbase.h
@@ -6,6 +6,7 @@
#ifndef _BOARDBASE_H
#define _BOARDBASE_H
+#include "jdlib/jdregex.h"
#include "skeleton/loadable.h"
#include <string>
@@ -107,7 +108,6 @@ namespace DBTREE
// m_subjecttxt = "subject.txt"
// m_ext = ".dat"
// m_id = "hogeboard"
- // m_charset = "MS932"
//
// 先頭に'/'を付けて最後に '/' は付けないことにフォーマットを統一
//
@@ -120,13 +120,12 @@ namespace DBTREE
std::string m_subjecttxt;
std::string m_ext;
std::string m_id;
- std::string m_charset;
std::string m_name; // 板名
// dat型のurlに変換する時のquery ( url_dat()で使用する )
- std::string m_query_dat;
- std::string m_query_cgi;
- std::string m_query_kako;
+ JDLIB::RegexPattern m_query_dat;
+ JDLIB::RegexPattern m_query_cgi;
+ JDLIB::RegexPattern m_query_kako;
// ローカルあぼーん情報(板内の全レス対象)
std::list< std::string > m_list_abone_id; // あぼーんするID
@@ -139,7 +138,8 @@ namespace DBTREE
std::list< std::string > m_list_abone_thread_remove; // あぼーんするスレのタイトル( dat 落ち判定用、remove_old_abone_thread()を参照せよ )
std::list< std::string > m_list_abone_word_thread; // あぼーんする文字列
std::list< std::string > m_list_abone_regex_thread; // あぼーんする正規表現
- int m_abone_number_thread; // レスの数
+ int m_abone_min_number_thread; // レスの数(最小)
+ int m_abone_max_number_thread; // レスの数(最大)
int m_abone_hour_thread; // スレ立てからの経過時間
// 読み込み用ローカルプロキシ設定
@@ -177,9 +177,9 @@ namespace DBTREE
std::list< std::string > m_url_update_views; // CORE::core_set_command( "update_board" ) を送信するビューのアドレス
JDLIB::Iconv* m_iconv;
char* m_rawdata;
- char* m_rawdata_left;
size_t m_lng_rawdata;
size_t m_lng_rawdata_left;
+ CharCode m_charcode_bak;
// 情報ファイルを読みこんだらtrueにして2度読みしないようにする
bool m_read_info;
@@ -228,7 +228,6 @@ namespace DBTREE
void set_subjecttxt( const std::string& str ){ m_subjecttxt = str; }
void set_ext( const std::string& str ){ m_ext = str; }
void set_id( const std::string& str ){ m_id = str; }
- void set_charset( const std::string& str ){ m_charset = str; }
// articleがスレあぼーんされているか
bool is_abone_thread( ArticleBase* article );
@@ -243,6 +242,10 @@ namespace DBTREE
// クッキー:HAPの更新 (クッキーをセットした時に実行)
virtual void update_hap(){}
+ // subject.txt の URLを取得
+ // (例) "http://www.hoge2ch.net/hogeboard/subject.txt"
+ std::string url_subject();
+
public:
BoardBase( const std::string& root, const std::string& path_board, const std::string& name );
@@ -292,7 +295,6 @@ namespace DBTREE
const std::string& get_path_board() const { return m_path_board; }
const std::string& get_ext() const { return m_ext; }
const std::string& get_id() const { return m_id; }
- const std::string& get_charset() const { return m_charset; }
const std::string& get_name() const { return m_name; }
void update_name( const std::string& name );
const std::string& get_subjecttxt() const { return m_subjecttxt; }
@@ -365,9 +367,9 @@ namespace DBTREE
// "http://www.hoge2ch.net/test/read.cgi/hogeboard/12345/12-15"
virtual std::string url_readcgi( const std::string& url, int num_from, int num_to );
- // subject.txt の URLを取得
- // (例) "http://www.hoge2ch.net/hogeboard/subject.txt"
- std::string url_subject();
+ // SETTING.TXT の URLを取得
+ // (例) "http://www.hoge2ch.net/hogeboard/SETTING.TXT"
+ virtual std::string url_settingtxt() { return {}; }
// ルートアドレス
// (例) "http://www.hoge2ch.net/hogeboard/" なら "http://www.hoge2ch.net/"
@@ -447,8 +449,9 @@ namespace DBTREE
const std::list< std::string >& get_abone_list_thread_remove(){ return m_list_abone_thread_remove; }
const std::list< std::string >& get_abone_list_word_thread(){ return m_list_abone_word_thread; }
const std::list< std::string >& get_abone_list_regex_thread(){ return m_list_abone_regex_thread; }
- int get_abone_number_thread(){ return m_abone_number_thread; }
- int get_abone_hour_thread(){ return m_abone_hour_thread; }
+ int get_abone_min_number_thread() { return m_abone_min_number_thread; }
+ int get_abone_max_number_thread() { return m_abone_max_number_thread; }
+ int get_abone_hour_thread() { return m_abone_hour_thread; }
// subject.txtのロード後にdat落ちしたスレッドをスレあぼーんのリストから取り除く
void remove_old_abone_thread();
@@ -463,7 +466,8 @@ namespace DBTREE
void reset_abone_thread( const std::list< std::string >& threads,
const std::list< std::string >& words,
const std::list< std::string >& regexs,
- const int number,
+ const int min_number,
+ const int max_number,
const int hour,
const bool redraw
);
@@ -592,7 +596,8 @@ namespace DBTREE
// レス数であぼーん(グローバル)
// 2ch以外の板ではキャンセルする
- virtual int get_abone_number_global() { return 0; }
+ virtual int get_abone_min_number_global(){ return 0; }
+ virtual int get_abone_max_number_global(){ return 0; }
};
}
diff --git a/src/dbtree/boardjbbs.cpp b/src/dbtree/boardjbbs.cpp
index c470d2ad..b17b6809 100644
--- a/src/dbtree/boardjbbs.cpp
+++ b/src/dbtree/boardjbbs.cpp
@@ -6,6 +6,8 @@
#include "boardjbbs.h"
#include "articlejbbs.h"
#include "articlehash.h"
+#include "settingloader.h"
+#include "ruleloader.h"
#include "jdlib/miscutil.h"
#include "jdlib/miscmsg.h"
@@ -13,6 +15,7 @@
#include "config/globalconf.h"
+#include "httpcode.h"
#include "global.h"
#include <sstream>
@@ -23,6 +26,8 @@ using namespace DBTREE;
BoardJBBS::BoardJBBS( const std::string& root, const std::string& path_board, const std::string& name )
: BoardBase( root, path_board, name )
+ , m_settingloader( NULL )
+ , m_ruleloader( NULL )
{
// dat のURLは特殊なので url_datpath()をオーバライドする
set_path_dat( "" );
@@ -33,7 +38,7 @@ BoardJBBS::BoardJBBS( const std::string& root, const std::string& path_board, co
set_subjecttxt( "subject.txt" );
set_ext( "" );
set_id( path_board.substr( 1 ) ); // 先頭の '/' を除く
- set_charset( "EUCJP-WIN" );
+ set_charcode( CHARCODE_EUCJP );
}
@@ -64,12 +69,9 @@ ArticleBase* BoardJBBS::append_article( const std::string& datbase, const std::s
{
if( empty() ) return get_article_null();
- ArticleBase* article = new DBTREE::ArticleJBBS( datbase, id, cached );
+ ArticleBase* article = new DBTREE::ArticleJBBS( datbase, id, cached, get_charcode() );
if( article ){
get_hash_article()->push( article );
-
- // 最大レス数セット
- article->set_number_max( get_number_max_res() );
}
else return get_article_null();
@@ -106,11 +108,11 @@ std::string BoardJBBS::create_newarticle_message( const std::string& subject, co
std::stringstream ss_post;
ss_post.clear();
- ss_post << "SUBJECT=" << MISC::charset_url_encode( subject, get_charset() )
- << "&submit=" << MISC::charset_url_encode( "新規書き込み", get_charset() )
- << "&NAME=" << MISC::charset_url_encode( name, get_charset() )
- << "&MAIL=" << MISC::charset_url_encode( mail, get_charset() )
- << "&MESSAGE=" << MISC::charset_url_encode( msg, get_charset() )
+ ss_post << "SUBJECT=" << MISC::url_encode( subject, get_charcode() )
+ << "&submit=" << MISC::url_encode( std::string( "新規書き込み" ), get_charcode() )
+ << "&NAME=" << MISC::url_encode( name, get_charcode() )
+ << "&MAIL=" << MISC::url_encode( mail, get_charcode() )
+ << "&MESSAGE=" << MISC::url_encode( msg, get_charcode() )
<< "&DIR=" << dir
<< "&BBS=" << bbs
<< "&TIME=" << get_time_modified();
@@ -147,13 +149,103 @@ std::string BoardJBBS::url_subbbscgi_new()
+std::string BoardJBBS::localrule()
+{
+ if( m_ruleloader ){
+ if( m_ruleloader->is_loading() ) return "ロード中です";
+ else if( m_ruleloader->get_code() == HTTP_OK || m_ruleloader->get_code() == HTTP_REDIRECT || m_ruleloader->get_code() == HTTP_MOVED_PERM ){
+ if( m_ruleloader->get_data().empty() ) return "ローカルルールはありません";
+ else return m_ruleloader->get_data();
+ }
+ else return "ロードに失敗しました : " + m_ruleloader->get_str_code();
+ }
+
+ return BoardBase::localrule();
+}
+
+
+
+//
+// SETTING.TXT のURL
+//
+// (例) "http://jbbs.shitaraba.net/bbs/api/setting.cgi/computer/123/"
+//
+std::string BoardJBBS::url_settingtxt()
+{
+ return get_root() + "/bbs/api/setting.cgi/" + get_id() + "/";
+}
+
+
+std::string BoardJBBS::settingtxt()
+{
+ if( m_settingloader ){
+ if( m_settingloader->is_loading() ) return "ロード中です";
+ else if( m_settingloader->get_code() == HTTP_OK || m_settingloader->get_code() == HTTP_REDIRECT || m_settingloader->get_code() == HTTP_MOVED_PERM ){
+ if( m_settingloader->get_data().empty() ) return "SETTING.TXTはありません";
+ else return m_settingloader->get_data();
+ }
+ else return "ロードに失敗しました : " + m_settingloader->get_str_code();
+ }
+
+ return BoardBase::settingtxt();
+}
+
+
+std::string BoardJBBS::default_noname()
+{
+ if( m_settingloader
+ && m_settingloader->get_code() == HTTP_OK ) return m_settingloader->default_noname();
+
+ return BoardBase::default_noname();
+}
+
+
+//
+// ローカルルールとSETTING.TXTをキャッシュから読み込む
+//
+// BoardBase::read_info()で呼び出す
+//
+void BoardJBBS::load_rule_setting()
+{
+#ifdef _DEBUG
+ std::cout << "BoardJBBS::load_rule_setting" << std::endl;
+#endif
+
+ if( ! m_ruleloader ) m_ruleloader = new RuleLoader( url_boardbase() );
+ m_ruleloader->load_text( CHARCODE_SJIS );
+
+ if( ! m_settingloader ) m_settingloader = new SettingLoader( url_boardbase() );
+ m_settingloader->load_text( get_charcode() );
+}
+
+
+//
+// SETTING.TXTをサーバからダウンロード(ローカルルールはダウンロードしない)
+//
+// 読み込むタイミングはsubject.txtを読み終わった直後( BoardBase::receive_finish() )
+//
+void BoardJBBS::download_rule_setting()
+{
+#ifdef _DEBUG
+ std::cout << "BoardJBBS::download_rule_setting" << std::endl;
+#endif
+
+ if( ! m_ruleloader ) m_ruleloader = new RuleLoader( url_boardbase() );
+ m_ruleloader->download_text( CHARCODE_SJIS );
+
+ if( ! m_settingloader ) m_settingloader = new SettingLoader( url_boardbase() );
+ m_settingloader->download_text( get_charcode() );
+}
+
+
+
//
// subject.txt から Aarticle のリストにアイテムを追加・更新
//
void BoardJBBS::parse_subject( const char* str_subject_txt )
{
#ifdef _DEBUG
- std::cout << "BoardJBBS::parse_subject\n";
+ std::cout << "BoardJBBS::parse_subject" << std::endl;
#endif
const char* pos = str_subject_txt;
@@ -212,9 +304,6 @@ void BoardJBBS::parse_subject( const char* str_subject_txt )
artinfo.id = MISC::remove_space( artinfo.id );
artinfo.subject.assign( str_subject, lng_subject );
- artinfo.subject = MISC::remove_space( artinfo.subject );
- artinfo.subject = MISC::replace_str( artinfo.subject, "&lt;", "<" );
- artinfo.subject = MISC::replace_str( artinfo.subject, "&gt;", ">" );
const auto num = std::atoi( str_num );
artinfo.number = ( num < CONFIG::get_max_resnumber() ) ? num : CONFIG::get_max_resnumber();
diff --git a/src/dbtree/boardjbbs.h b/src/dbtree/boardjbbs.h
index 7c2ec95b..2ee635c5 100644
--- a/src/dbtree/boardjbbs.h
+++ b/src/dbtree/boardjbbs.h
@@ -11,11 +11,18 @@
namespace DBTREE
{
+ class SettingLoader;
+ class RuleLoader;
+
class BoardJBBS : public BoardBase
{
+ SettingLoader* m_settingloader;
+ RuleLoader* m_ruleloader;
+
public:
BoardJBBS( const std::string& root, const std::string& path_board,const std::string& name );
+ ~BoardJBBS() noexcept = default;
std::string url_datpath() override;
@@ -29,12 +36,24 @@ namespace DBTREE
// 新スレ作成用のsubbbscgi のURL
std::string url_subbbscgi_new() override;
+ // ローカルルール
+ std::string localrule() override;
+
+ // SETTING.TXT のURL
+ std::string url_settingtxt() override;
+ // SETTING.TXT
+ std::string settingtxt() override;
+ std::string default_noname() override;
+
private:
bool is_valid( const std::string& filename ) override;
ArticleBase* append_article( const std::string& datbase, const std::string& id, const bool cached ) override;
void parse_subject( const char* str_subject_txt ) override;
void regist_article( const bool is_online ) override;
+
+ void load_rule_setting() override;
+ void download_rule_setting() override;
};
}
diff --git a/src/dbtree/boardlocal.cpp b/src/dbtree/boardlocal.cpp
index 9d44c76f..5841f6f2 100644
--- a/src/dbtree/boardlocal.cpp
+++ b/src/dbtree/boardlocal.cpp
@@ -24,8 +24,7 @@ BoardLocal::BoardLocal( const std::string& root, const std::string& path_board,
}
-BoardLocal::~BoardLocal() noexcept
-{}
+BoardLocal::~BoardLocal() noexcept = default;
//
@@ -71,6 +70,12 @@ std::string BoardLocal::url_readcgi( const std::string& url, int num_from, int n
}
+std::string BoardLocal::url_datpath()
+{
+ return std::string();
+}
+
+
void BoardLocal::download_subject( const std::string& url_update_view, const bool )
{
// ダウンロードを実行しない
@@ -86,7 +91,7 @@ ArticleBase* BoardLocal::append_article( const std::string& datbase, const std::
<< ", id = " << id << std::endl;
#endif
- ArticleBase* article = new DBTREE::ArticleLocal( datbase, id );
+ ArticleBase* article = new DBTREE::ArticleLocal( datbase, id, get_charcode() );
if( article ){
get_hash_article()->push( article );
diff --git a/src/dbtree/boardlocal.h b/src/dbtree/boardlocal.h
index 4c35ddd4..ae5eac0c 100644
--- a/src/dbtree/boardlocal.h
+++ b/src/dbtree/boardlocal.h
@@ -23,6 +23,7 @@ namespace DBTREE
std::string url_dat( const std::string& url, int& num_from, int& num_to, std::string& num_str ) override;
std::string url_readcgi( const std::string& url, int num_from, int num_to ) override;
+ std::string url_datpath() override;
void download_subject( const std::string& url_update_view, const bool ) override;
diff --git a/src/dbtree/boardmachi.cpp b/src/dbtree/boardmachi.cpp
index 8afc9c70..76993a15 100644
--- a/src/dbtree/boardmachi.cpp
+++ b/src/dbtree/boardmachi.cpp
@@ -33,7 +33,7 @@ BoardMachi::BoardMachi( const std::string& root, const std::string& path_board,
set_subjecttxt( "subject.txt" );
set_ext( "" );
set_id( path_board.substr( 1 ) ); // 先頭の '/' を除く
- set_charset( "MS932" );
+ set_charcode( CHARCODE_SJIS );
}
@@ -81,12 +81,9 @@ ArticleBase* BoardMachi::append_article( const std::string& datbase, const std::
{
if( empty() ) return get_article_null();
- ArticleBase* article = new DBTREE::ArticleMachi( datbase, id, cached );
+ ArticleBase* article = new DBTREE::ArticleMachi( datbase, id, cached, get_charcode() );
if( article ){
get_hash_article()->push( article );
-
- // 最大レス数セット
- article->set_number_max( get_number_max_res() );
}
else return get_article_null();
@@ -272,9 +269,6 @@ void BoardMachi::parse_subject( const char* str_subject_txt )
artinfo.id = MISC::remove_space( artinfo.id );
artinfo.subject.assign( str_subject, lng_subject );
- artinfo.subject = MISC::remove_space( artinfo.subject );
- artinfo.subject = MISC::replace_str( artinfo.subject, "&lt;", "<" );
- artinfo.subject = MISC::replace_str( artinfo.subject, "&gt;", ">" );
const auto num = std::atoi( str_num );
artinfo.number = ( num < CONFIG::get_max_resnumber() ) ? num : CONFIG::get_max_resnumber();
diff --git a/src/dbtree/boardmachi.h b/src/dbtree/boardmachi.h
index f382fccf..74e15ea6 100644
--- a/src/dbtree/boardmachi.h
+++ b/src/dbtree/boardmachi.h
@@ -16,6 +16,7 @@ namespace DBTREE
public:
BoardMachi( const std::string& root, const std::string& path_board,const std::string& name );
+ ~BoardMachi() noexcept = default;
// url がこの板のものかどうか
bool equal( const std::string& url ) override;
diff --git a/src/dbtree/interface.cpp b/src/dbtree/interface.cpp
index cd3ae930..c9770485 100644
--- a/src/dbtree/interface.cpp
+++ b/src/dbtree/interface.cpp
@@ -60,12 +60,6 @@ DBTREE::ArticleBase* DBTREE::get_article( const std::string& url )
//////////////////////////////////////
-std::string DBTREE::url_subject( const std::string& url )
-{
- return DBTREE::get_board( url )->url_subject();
-}
-
-
std::string DBTREE::url_root( const std::string& url )
{
return DBTREE::get_board( url )->url_root();
@@ -139,6 +133,13 @@ std::string DBTREE::url_subbbscgi_new( const std::string& url )
}
+std::string DBTREE::url_settingtxt( const std::string& url )
+{
+ return DBTREE::get_board( url )->url_settingtxt();
+}
+
+
+
// 簡易版
std::string DBTREE::is_board_moved( const std::string& url )
{
@@ -230,13 +231,13 @@ time_t DBTREE::get_time_modified()
}
-std::string DBTREE::board_path( const std::string& url )
+const std::string& DBTREE::board_path( const std::string& url )
{
return DBTREE::get_board( url )->get_path_board();
}
-std::string DBTREE::board_id( const std::string& url )
+const std::string& DBTREE::board_id( const std::string& url )
{
return DBTREE::get_board( url )->get_id();
}
@@ -248,7 +249,7 @@ time_t DBTREE::board_time_modified( const std::string& url )
}
// 板の更新時間( 文字列 )
-std::string DBTREE::board_date_modified( const std::string& url )
+const std::string& DBTREE::board_date_modified( const std::string& url )
{
return DBTREE::get_board( url )->get_date_modified();
}
@@ -280,21 +281,27 @@ void DBTREE::board_set_modified_setting( const std::string& url, const std::stri
}
-std::string DBTREE::board_name( const std::string& url )
+const std::string& DBTREE::board_name( const std::string& url )
{
return DBTREE::get_board( url )->get_name();
}
-std::string DBTREE::board_subjecttxt( const std::string& url )
+const std::string& DBTREE::board_subjecttxt( const std::string& url )
{
return DBTREE::get_board( url )->get_subjecttxt();
}
-std::string DBTREE::board_charset( const std::string& url )
+CharCode DBTREE::board_charcode( const std::string& url )
{
- return DBTREE::get_board( url )->get_charset();
+ return DBTREE::get_board( url )->get_charcode();
+}
+
+
+void DBTREE::board_set_charcode( const std::string& url, const CharCode charcode )
+{
+ return DBTREE::get_board( url )->set_charcode( charcode );
}
@@ -320,7 +327,7 @@ void DBTREE::board_reset_list_cookies_for_write( const std::string& url )
DBTREE::get_board( url )->reset_list_cookies_for_write();
}
-std::string DBTREE::board_keyword_for_write( const std::string& url )
+const std::string& DBTREE::board_keyword_for_write( const std::string& url )
{
return DBTREE::get_board( url )->get_keyword_for_write();
}
@@ -338,13 +345,13 @@ void DBTREE::board_analyze_keyword_for_write( const std::string& url, const std:
}
-std::string DBTREE::board_basicauth( const std::string& url )
+const std::string& DBTREE::board_basicauth( const std::string& url )
{
return DBTREE::get_board( url )->get_basicauth();
}
-std::string DBTREE::board_ext( const std::string& url )
+const std::string& DBTREE::board_ext( const std::string& url )
{
return DBTREE::get_board( url )->get_ext();
}
@@ -362,7 +369,7 @@ int DBTREE::board_code( const std::string& url )
}
-std::string DBTREE::board_str_code( const std::string& url )
+const std::string& DBTREE::board_str_code( const std::string& url )
{
return DBTREE::get_board( url )->get_str_code();
}
@@ -741,9 +748,14 @@ const std::list< std::string >& DBTREE::get_abone_list_regex_thread( const std::
return DBTREE::get_board( url )->get_abone_list_regex_thread();
}
-int DBTREE::get_abone_number_thread( const std::string& url )
+int DBTREE::get_abone_min_number_thread( const std::string& url )
{
- return DBTREE::get_board( url )->get_abone_number_thread();
+ return DBTREE::get_board( url )->get_abone_min_number_thread();
+}
+
+int DBTREE::get_abone_max_number_thread( const std::string& url )
+{
+ return DBTREE::get_board( url )->get_abone_max_number_thread();
}
int DBTREE::get_abone_hour_thread( const std::string& url )
@@ -766,12 +778,13 @@ void DBTREE::reset_abone_thread( const std::string& url,
const std::list< std::string >& threads,
const std::list< std::string >& words,
const std::list< std::string >& regexs,
- const int number,
+ const int min_number,
+ const int max_number,
const int hour,
const bool redraw
)
{
- DBTREE::get_board( url )->reset_abone_thread( threads, words, regexs, number, hour, redraw );
+ DBTREE::get_board( url )->reset_abone_thread( threads, words, regexs, min_number, max_number, hour, redraw );
}
/////////////////////////////////////////////////
@@ -835,7 +848,19 @@ void DBTREE::article_set_date_modified( const std::string& url, const std::strin
DBTREE::get_article( url )->set_date_modified( date );
}
-int DBTREE::article_hour( const std::string& url )
+// スレの文字コード
+CharCode DBTREE::article_charcode( const std::string& url )
+{
+ return DBTREE::get_article( url )->get_charcode();
+}
+
+// スレの文字コードをセット
+void DBTREE::article_set_charcode( const std::string& url, const CharCode charcode )
+{
+ DBTREE::get_article( url )->set_charcode( charcode );
+}
+
+int DBTREE::article_hour( const std::string& url )
{
return DBTREE::get_article( url )->get_hour();
}
@@ -875,11 +900,15 @@ std::string DBTREE::article_ext_err( const std::string& url )
return DBTREE::get_article( url )->get_ext_err();
}
-std::string DBTREE::article_subject( const std::string& url )
+const std::string& DBTREE::article_subject( const std::string& url )
{
return DBTREE::get_article( url )->get_subject();
}
+const std::string& DBTREE::article_modified_subject( const std::string& url, const bool renew )
+{
+ return DBTREE::get_article( url )->get_modified_subject( renew );
+}
int DBTREE::article_number( const std::string& url )
{
@@ -906,6 +935,16 @@ int DBTREE::article_number_new( const std::string& url )
return DBTREE::get_article( url )->get_number_new();
}
+int DBTREE::article_number_max( const std::string& url )
+{
+ return DBTREE::get_article( url )->get_number_max();
+}
+
+void DBTREE::article_set_number_max( const std::string& url, int max )
+{
+ DBTREE::get_article( url )->set_number_max( max );
+}
+
bool DBTREE::article_is_loading( const std::string& url )
{
return DBTREE::get_article( url )->is_loading();
@@ -950,6 +989,13 @@ void DBTREE::article_clear_post_history( const std::string& url )
}
+// NodeTree削除
+void DBTREE::article_clear_nodetree( const std::string& url )
+{
+ DBTREE::get_article( url )->unlock_impl();
+}
+
+
// ユーザーエージェント
// ダウンロード用
const std::string& DBTREE::get_agent( const std::string& url )
@@ -1182,10 +1228,11 @@ void DBTREE::reset_abone( const std::string& url,
const std::list< std::string >& regexs,
const std::vector< char >& vec_abone_res,
const bool transparent, const bool chain, const bool age,
+ const bool default_name, const bool noid,
const bool board, const bool global
)
{
- DBTREE::get_article( url )->reset_abone( ids, names, words, regexs, vec_abone_res, transparent, chain, age, board, global );
+ DBTREE::get_article( url )->reset_abone( ids, names, words, regexs, vec_abone_res, transparent, chain, age, default_name, noid, board, global );
}
@@ -1251,6 +1298,32 @@ void DBTREE::set_abone_age( const std::string& url, const bool set )
}
+// デフォルト名無しあぼーん
+bool DBTREE::get_abone_default_name( const std::string& url )
+{
+ return DBTREE::get_article( url )->get_abone_default_name();
+}
+
+
+void DBTREE::set_abone_default_name( const std::string& url, const bool set )
+{
+ DBTREE::get_article( url )->set_abone_default_name( set );
+}
+
+
+// ID無しあぼーん
+bool DBTREE::get_abone_noid( const std::string& url )
+{
+ return DBTREE::get_article( url )->get_abone_noid();
+}
+
+
+void DBTREE::set_abone_noid( const std::string& url, const bool set )
+{
+ DBTREE::get_article( url )->set_abone_noid( set );
+}
+
+
// 板レベルでのあぼーん
bool DBTREE::get_abone_board( const std::string& url )
{
diff --git a/src/dbtree/interface.h b/src/dbtree/interface.h
index f4241c36..93dbf71f 100644
--- a/src/dbtree/interface.h
+++ b/src/dbtree/interface.h
@@ -7,6 +7,7 @@
#ifndef _INTERFACE_H
#define _INTERFACE_H
+#include "charcode.h"
#include "etcboardinfo.h"
#include <string>
@@ -37,7 +38,6 @@ namespace DBTREE
ArticleBase* get_article( const std::string& url );
// urlの変換関係
- std::string url_subject( const std::string& url ); // 板の subject.txt の URL
std::string url_root( const std::string& url );
std::string url_boardbase( const std::string& url );
std::string url_datbase( const std::string& url );
@@ -58,6 +58,8 @@ namespace DBTREE
std::string url_bbscgi_new( const std::string& url );
std::string url_subbbscgi_new( const std::string& url );
+ std::string url_settingtxt( const std::string& url );
+
// 板が移転したかチェックする
// 移転した時は移転後のURLを返す
std::string is_board_moved( const std::string& url );
@@ -91,30 +93,31 @@ namespace DBTREE
time_t get_time_modified(); // bbsmenuの更新時間( time_t )
// board 系
- std::string board_path( const std::string& url );
- std::string board_id( const std::string& url );
+ const std::string& board_path( const std::string& url );
+ const std::string& board_id( const std::string& url );
time_t board_time_modified( const std::string& url ); // 板の更新時間( time_t )
- std::string board_date_modified( const std::string& url ); // 板の更新時間( 文字列 )
+ const std::string& board_date_modified( const std::string& url ); // 板の更新時間( 文字列 )
void board_set_date_modified( const std::string& url, const std::string& date ); // 板の更新時間( 文字列 )をセット
const std::string& board_get_modified_localrule( const std::string& url );
void board_set_modified_localrule( const std::string& url, const std::string& modified );
const std::string& board_get_modified_setting( const std::string& url );
void board_set_modified_setting( const std::string& url, const std::string& modified );
- std::string board_name( const std::string& url );
- std::string board_subjecttxt( const std::string& url );
- std::string board_charset( const std::string& url );
+ const std::string& board_name( const std::string& url );
+ const std::string& board_subjecttxt( const std::string& url );
+ CharCode board_charcode( const std::string& url );
+ void board_set_charcode( const std::string& url, const CharCode charcode );
std::string board_cookie_for_write( const std::string& url );
const std::list< std::string >& board_list_cookies_for_write( const std::string& url );
void board_set_list_cookies_for_write( const std::string& url, const std::list< std::string>& list_cookies );
void board_reset_list_cookies_for_write( const std::string& url );
- std::string board_keyword_for_write( const std::string& url );
+ const std::string& board_keyword_for_write( const std::string& url );
void board_set_keyword_for_write( const std::string& url, const std::string& keyword );
void board_analyze_keyword_for_write( const std::string& url, const std::string& html );
- std::string board_basicauth( const std::string& url );
- std::string board_ext( const std::string& url );
+ const std::string& board_basicauth( const std::string& url );
+ const std::string& board_ext( const std::string& url );
int board_status( const std::string& url );
int board_code( const std::string& url );
- std::string board_str_code( const std::string& url );
+ const std::string& board_str_code( const std::string& url );
void board_save_info( const std::string& url );
void board_download_subject( const std::string& url, const std::string& url_update_view );
void board_read_subject_from_cache( const std::string& url );
@@ -208,6 +211,8 @@ namespace DBTREE
time_t article_time_modified( const std::string& url ); // スレの更新時間( time_t )
std::string article_date_modified( const std::string& url ); // スレの更新時間( 文字列 )
void article_set_date_modified( const std::string& url, const std::string& date ); // スレの更新時間( 文字列 )をセット
+ CharCode article_charcode( const std::string& url );
+ void article_set_charcode( const std::string& url, const CharCode charcode );
int article_hour( const std::string& url );
time_t article_write_time( const std::string& url );
std::string article_write_date( const std::string& url );
@@ -215,12 +220,15 @@ namespace DBTREE
int article_code( const std::string& url );
std::string article_str_code( const std::string& url );
std::string article_ext_err( const std::string& url );
- std::string article_subject( const std::string& url );
+ const std::string& article_subject( const std::string& url );
+ const std::string& article_modified_subject( const std::string& url, const bool renew = false );
int article_number( const std::string& url );
int article_number_load( const std::string& url );
int article_number_seen( const std::string& url );
void article_set_number_seen( const std::string& url, int seen );
int article_number_new( const std::string& url );
+ int article_number_max( const std::string& url );
+ void article_set_number_max( const std::string& url, int max );
bool article_is_loading( const std::string& url );
bool article_is_checking_update( const std::string& url );
void article_download_dat( const std::string& url, const bool check_update );
@@ -245,6 +253,9 @@ namespace DBTREE
void article_update_writetime( const std::string& url );
size_t article_lng_dat( const std::string& url );
+ // NodeTree削除
+ void article_clear_nodetree( const std::string& url );
+
// ユーザーエージェント
const std::string& get_agent( const std::string& url ); // ダウンロード用
const std::string& get_agent_w( const std::string& url ); // 書き込み用
@@ -328,7 +339,8 @@ namespace DBTREE
const std::list< std::string >& get_abone_list_word_thread( const std::string& url );
const std::list< std::string >& get_abone_list_regex_thread( const std::string& url );
const std::unordered_set< int >& get_abone_reses( const std::string& url );
- int get_abone_number_thread( const std::string& url );
+ int get_abone_min_number_thread( const std::string& url );
+ int get_abone_max_number_thread( const std::string& url );
int get_abone_hour_thread( const std::string& url );
// subject.txtのロード後にdat落ちしたスレッドをスレあぼーんのリストから取り除く
@@ -344,7 +356,8 @@ namespace DBTREE
const std::list< std::string >& threads,
const std::list< std::string >& words,
const std::list< std::string >& regexs,
- const int number, const int hour, const bool redraw );
+ const int min_number, const int max_number,
+ const int hour, const bool redraw );
//
// 各articlebase別のあぼーん情報
@@ -373,6 +386,7 @@ namespace DBTREE
const std::list< std::string >& regexs,
const std::vector< char >& vec_abone_res,
const bool transparent, const bool chain, const bool age,
+ const bool default_name, const bool noid,
const bool board, const bool global
);
@@ -394,6 +408,14 @@ namespace DBTREE
bool get_abone_age( const std::string& url );
void set_abone_age( const std::string& url, const bool set );
+ // デフォルト名無しあぼーん
+ bool get_abone_default_name( const std::string& url );
+ void set_abone_default_name( const std::string& url, const bool set );
+
+ // ID無しあぼーん
+ bool get_abone_noid( const std::string& url );
+ void set_abone_noid( const std::string& url, const bool set );
+
// 板レベルでのあぼーん
bool get_abone_board( const std::string& url );
void set_abone_board( const std::string& url, const bool set );
diff --git a/src/dbtree/node.h b/src/dbtree/node.h
index 1fb28af6..6f179c2d 100644
--- a/src/dbtree/node.h
+++ b/src/dbtree/node.h
@@ -29,11 +29,9 @@ namespace DBTREE
NODE_DIV, // div
NODE_IMG, // img
- // スペース(幅0)
- NODE_ZWSP,
-
- // 連続半角スペース
- NODE_MULTISP,
+ NODE_SP, // スペース
+ NODE_ZWSP, // スペース(幅0)
+ NODE_MULTISP, // 連続半角スペース
// 水平タブ(0x09)
NODE_HTAB,
@@ -79,6 +77,7 @@ namespace DBTREE
bool sage; // メール欄がsageか
int num_id_name; // 同じIDのレスの個数( = 発言数 )
+ NODE* pre_id_name_header; // 同じIDを持つ一つ前のヘッダノードのアドレス
NODE* block[ BLOCK_NUM ];
};
@@ -117,6 +116,7 @@ namespace DBTREE
char* text;
unsigned char color_text; // 色
+ unsigned char color_back; // 背景色
bool bold;
char fontid; // fontid.h
diff --git a/src/dbtree/nodetree2ch.cpp b/src/dbtree/nodetree2ch.cpp
index 0926097e..1595e40c 100644
--- a/src/dbtree/nodetree2ch.cpp
+++ b/src/dbtree/nodetree2ch.cpp
@@ -9,6 +9,7 @@
#include "jdlib/jdregex.h"
#include "jdlib/loaderdata.h"
#include "jdlib/miscutil.h"
+#include "jdlib/miscmsg.h"
#include "config/globalconf.h"
@@ -24,11 +25,11 @@ using namespace DBTREE;
enum
{
MODE_NORMAL = 0,
- MODE_OFFLAW,
- MODE_OFFLAW2,
+ MODE_CGI,
+ MODE_OLDURL,
MODE_KAKO_GZ,
MODE_KAKO,
- MODE_OLDURL
+ MODE_KAKO_EXT,
};
@@ -38,6 +39,7 @@ NodeTree2ch::NodeTree2ch( const std::string& url, const std::string& org_url,
, m_org_url( org_url )
, m_since_time( since_time )
, m_mode( MODE_NORMAL )
+ , m_res_number_max( -1 )
{
#ifdef _DEBUG
std::cout << "NodeTree2ch::NodeTree2ch url = " << url << std::endl
@@ -61,31 +63,73 @@ NodeTree2ch::~NodeTree2ch()
//
// 先頭にrawモードのステータスが入っていたら取り除く
//
-char* NodeTree2ch::process_raw_lines( char* rawlines )
+char* NodeTree2ch::process_raw_lines( char* rawlines, size_t& size )
{
- char* pos = rawlines;
-
- if( m_mode == MODE_OFFLAW ){
- // rokka独自のステータスが入っている
-
- int status = 0;
- if( strncmp( pos, "Success", 7 ) == 0 ) status = 1;
- if( strncmp( pos, "Error", 5 ) == 0 ) status = 2;
-
+ if( ! is_loading() && memcmp( rawlines, "<dt>", 4 ) == 0 ){
#ifdef _DEBUG
- std::cout << "NodeTree2ch::process_raw_lines : raw mode status = " << status << std::endl;
+ std::cout << "NodeTree2ch::process_raw_lines ignore HTML lines" << std::endl;
#endif
+ *rawlines = '\0';
+ }
+ else if( ! is_loading() && memcmp( rawlines, "ng (", 4 ) == 0
+ && strstr( rawlines, "<>" ) == NULL ){
+ set_code( HTTP_ERR );
+ set_str_code( rawlines );
+ MISC::ERRMSG( rawlines );
+ *rawlines = '\0';
+ }
+ else if( size == 16 && memcmp( rawlines, "Dat doesnt exist", 16 ) == 0 ){
+ set_ext_err( rawlines );
+ *rawlines = '\0';
+ }
+ else if( m_mode == MODE_NORMAL && is_loading() && ! id_header() ){
+ char *l1, *l2;
+ if( ! ( l1 = strchr( rawlines, '\n' ) ) ) return rawlines;
+ if( ! ( l2 = strchr( l1 + 1, '\n' ) ) || *( l2 + 1 ) != '\0' ) return rawlines;
- if( status != 0 ){
- pos = skip_status_line( pos, status );
+ char *id = strstr( l1 + 1, " ID:\?\?\?\?\?\?\?\?<>" );
+ if( id && id < l2 ){
+ // ログ落ち案内レス
+ m_operate_info = l1 + 1; // レスをプールする
+ *( l1 + 1 ) = '\0';
}
}
- else {
- pos = NodeTree2chCompati::process_raw_lines( rawlines );
+ return rawlines;
+}
+
+
+//
+// 拡張属性を取り出す
+//
+void NodeTree2ch::parse_extattr( const char* str, const int lng )
+{
+ const char* pos = str;
+
+ while( pos < str + lng && ( pos = (const char *)memchr( pos, '<', str + lng - pos ) ) != NULL ){
+ if( memcmp( pos, "<hr>VIPQ2_EXTDAT: ", 18 ) == 0 ){ pos += 18; break; }
+ ++pos;
}
- return pos;
+ if( pos != NULL && pos < str + lng ){
+ JDLIB::Regex regex;
+ const size_t offset = 0;
+ const bool icase = false; // 大文字小文字区別しない
+ const bool newline = true; // . に改行をマッチさせない
+ const bool usemigemo = false; // migemo使用
+ const bool wchar = false; // 全角半角の区別をしない
+
+ std::string extattr( pos, str + lng - pos );
+ if( regex.exec( "[^:]+:[^:]+:([^:]+):[^ ]+ EXT was configured",
+ extattr.c_str(), offset, icase, newline, usemigemo, wchar ) ){
+
+ // 最大レス数を取得
+ if( regex.str( 1 ) == "V" ) m_res_number_max = 0;
+ else if( regex.str( 1 )[ 0 ] >= '0' && regex.str( 1 )[ 0 ] <= '9' ){
+ m_res_number_max = atoi( regex.str( 1 ).c_str() );
+ }
+ }
+ }
}
@@ -99,98 +143,60 @@ void NodeTree2ch::create_loaderdata( JDLIB::LOADERDATA& data )
#endif
- data.url = std::string();
data.byte_readfrom = 0;
- //rokka使用 (旧offlawは廃止)
- if( m_mode == MODE_OFFLAW ){
-
- JDLIB::Regex regex;
- const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
-
- if( ! regex.exec( "(https?://)([^/\\.]+)(\\.[^/]+)(/.*)/dat(/.*)\\.dat$", m_org_url, offset, icase, newline, usemigemo, wchar ) ) return;
-
- // http://rokka(.2ch.net|.bbspink.com)/<SERVER NAME>/<BOARD NAME>/<DAT NUMBER>/<OPTIONS>?sid=<SID>
- std::ostringstream ss;
- ss << regex.str( 1 ) << "rokka" << regex.str( 3 ) << "/" << regex.str( 2 )
- << regex.str( 4 ) << regex.str( 5 );
-
- std::string sid = CORE::get_login2ch()->get_sessionid();
- ss << "/?sid=" << MISC::url_encode( sid.c_str(), sid.length() );
-
- // レジューム設定
- // レジュームを有りにして、サーバが range を無視して送ってきた場合と同じ処理をする
- if( get_lng_dat() ) {
- set_resume( true );
- }
- else set_resume( false );
-
- data.url = ss.str();
- }
-
- //offlaw2 使用
- else if( m_mode == MODE_OFFLAW2 ){
-
- JDLIB::Regex regex;
- const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
-
- if( ! regex.exec( "(https?://[^/]*)/(.*)/dat/(.*)\\.dat$", m_org_url, offset, icase, newline, usemigemo, wchar ) ) return;
-
- std::ostringstream ss;
- ss << regex.str( 1 ) << "/test/offlaw2.so?shiro=kuma&sid=ERROR&bbs=" << regex.str( 2 )
- << "&key=" << regex.str( 3 );
-
- // レジューム設定
- // レジュームを有りにして、サーバが range を無視して送ってきた場合と同じ処理をする
- if( get_lng_dat() ) {
- set_resume( true );
- }
- else set_resume( false );
-
- data.url = ss.str();
- }
+ JDLIB::Regex regex;
+ const size_t offset = 0;
+ const bool icase = false;
+ const bool newline = true;
+ const bool usemigemo = false;
+ const bool wchar = false;
+ // ( rokka, 旧offlaw, offlaw2は廃止 )
// 過去ログ倉庫使用
- else if( m_mode == MODE_KAKO_GZ || m_mode == MODE_KAKO ){
-
- JDLIB::Regex regex;
- const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
+ if( m_mode == MODE_KAKO_GZ || m_mode == MODE_KAKO ){
if( ! regex.exec( "(https?://[^/]*)(/.*)/dat(/.*)\\.dat$", m_org_url, offset, icase, newline, usemigemo, wchar ) ) return;
const int id = atoi( regex.str( 3 ).c_str() + 1 );
- std::ostringstream ss;
+ std::string url;
// スレIDが10桁の場合 → http://サーバ/板ID/kako/IDの上位4桁/IDの上位5桁/ID.dat.gz
- if( id / 1000000000 ) ss << regex.str( 1 ) << regex.str( 2 ) << "/kako/" << ( id / 1000000 ) << "/" << ( id / 100000 ) << regex.str( 3 );
+ if( id / 1000000000 ) url = regex.str( 1 ) + regex.str( 2 ) + "/kako/" + MISC::itostr( id / 1000000 ) + "/" + MISC::itostr( id / 100000 ) + regex.str( 3 );
// スレIDが9桁の場合 → http://サーバ/板ID/kako/IDの上位3桁/ID.dat.gz
- else ss << regex.str( 1 ) << regex.str( 2 ) << "/kako/" << ( id / 1000000 ) << regex.str( 3 );
+ else url = regex.str( 1 ) + regex.str( 2 ) + "/kako/" + MISC::itostr( id / 1000000 ) + regex.str( 3 );
- if( m_mode == MODE_KAKO_GZ ) ss << ".dat.gz";
- else ss << ".dat";
+ if( m_mode == MODE_KAKO_GZ ) url += ".dat.gz";
+ else url += ".dat";
- // レジュームは無し
- set_resume( false );
+ data.url = url;
- data.url = ss.str();
+ // レジューム設定
+ if( get_lng_dat() ) set_resume( true );
+ else set_resume( false );
+ }
+
+ else if( m_mode == MODE_KAKO_EXT ){
+ if( ! regex.exec( "https?://([^./]+)\\.[^/]+/(.*)/dat/(.*)\\.dat$", m_org_url, offset, icase, newline, usemigemo, wchar ) ) return;
+
+ std::string cmd = CONFIG::get_url_external_log();
+ cmd = MISC::replace_str( cmd, "$OLDHOST", regex.str( 1 ) );
+ cmd = MISC::replace_str( cmd, "$BBSNAME", regex.str( 2 ) );
+ cmd = MISC::replace_str( cmd, "$DATNAME", regex.str( 3 ) );
+
+ data.url = cmd;
+
+ // レジューム設定
+ if( get_lng_dat() ) set_resume( true );
+ else set_resume( false );
}
// 普通もしくは旧URLからの読み込み
else{
+ data.url = ( m_mode == MODE_OLDURL ) ? m_org_url : get_url();
+
// レジューム設定
// 1byte前からレジュームして '\n' が返ってこなかったらあぼーんがあったってこと
if( get_lng_dat() ) {
@@ -198,28 +204,36 @@ void NodeTree2ch::create_loaderdata( JDLIB::LOADERDATA& data )
set_resume( true );
}
else set_resume( false );
-
- data.url = ( m_mode == MODE_OLDURL ) ? m_org_url : get_url();
}
#ifdef _DEBUG
std::cout << "load from " << data.url << std::endl;
#endif
+ if( !CONFIG::get_url_login2ch().compare( 0, CONFIG::get_url_login2ch().length(), data.url, 0, CONFIG::get_url_login2ch().length() ) ){
+ if( data.agent.empty() ) data.agent = CONFIG::get_agent_for2ch();
- data.agent = DBTREE::get_agent( get_url() );
+ if( CONFIG::get_use_proxy_for2ch() ){
+ data.host_proxy = CONFIG::get_proxy_for2ch();
+ data.port_proxy = CONFIG::get_proxy_port_for2ch();
+ }
+ data.basicauth_proxy = CONFIG::get_proxy_basicauth_for2ch();
+ }
+ else{
+ if( data.agent.empty() ) data.agent = DBTREE::get_agent( data.url );
+
+ data.host_proxy = DBTREE::get_proxy_host( data.url );
+ data.port_proxy = DBTREE::get_proxy_port( data.url );
+ data.basicauth_proxy = DBTREE::get_proxy_basicauth( data.url );
+ }
+
+ data.size_buf = CONFIG::get_loader_bufsize();
+ data.timeout = CONFIG::get_loader_timeout();
#ifdef _DEBUG
std::cout << "agent = " << data.agent << std::endl;
#endif
- data.host_proxy = DBTREE::get_proxy_host( get_url() );
- data.port_proxy = DBTREE::get_proxy_port( get_url() );
- data.basicauth_proxy = DBTREE::get_proxy_basicauth( get_url() );
-
- data.size_buf = CONFIG::get_loader_bufsize();
- data.timeout = CONFIG::get_loader_timeout();
-
if( ! get_date_modified().empty() ) data.modified = get_date_modified();
}
@@ -234,87 +248,83 @@ void NodeTree2ch::receive_finish()
<< "mode = " << m_mode << " code = " << get_code() << std::endl;
#endif
- // 更新チェックではない、オンラインの場合は offlaw や 過去ログ倉庫から取得出来るか試みる
+ // 保留データを処理する
+ sweep_buffer();
+
+ // 更新チェックではない、オンラインの場合は read.cgi や 過去ログ倉庫から取得出来るか試みる
if( ! is_checking_update()
&& SESSION::is_online()
- && ( get_code() == HTTP_REDIRECT || get_code() == HTTP_MOVED_PERM || get_code() == HTTP_NOT_FOUND
- || ( ( m_mode == MODE_OFFLAW || m_mode == MODE_OFFLAW2 )
- && ! get_ext_err().empty() ) // rokka or offlaw2 読み込み失敗
+ && ( get_code() == HTTP_REDIRECT || get_code() == HTTP_MOVED_PERM
+ || get_code() == HTTP_NOT_FOUND || get_code() == HTTP_NOT_IMPREMENTED
+ || ( ( m_mode == MODE_KAKO || m_mode == MODE_KAKO_GZ )
+ && get_code() == HTTP_AUTH_REQ ) // 過去ログ読み込み失敗
+ || ( m_mode == MODE_CGI && get_code() == HTTP_ORIGN_ERR )
+ || ! get_ext_err().empty() // スレが存在しない
)
){
/*
-
- ・スレIDが10桁の場合 → http://サーバ/板ID/kako/IDの上位4桁/IDの上位5桁/ID.dat.gz
-
- (例) http://HOGE.2ch.net/test/read.cgi/hoge/1234567890/ を取得
-
- (1) http://HOGE.2ch.net/hoge/dat/1234567890.dat から dat を取得。302で●がある場合(2-1)、旧URLがある場合(2-2)、無い場合は(2-3)へ(※)
-
- (2-1) offlaw.cgiを使って取得
-
- (2-2) 旧URLから取得
-
- (2-3) http://HOGE.2ch.net/hoge/kako/1234/12345/1234567890.dat.gz から取得。302なら(3)へ
-
- (3) http://HOGE.2ch.net/hoge/kako/1234/12345/1234567890.dat から取得
+ (1) 読み込み( dat直接, read.cgi, API )
+ (1-1) 旧URLがある場合はそのURLで再取得
+ (2) 過去ログ倉庫(gz)から読み込み (※1)
+ ・スレIDが10桁の場合 → http://サーバ/板ID/kako/IDの上位4桁/IDの上位5桁/ID.dat.gz
+ ・スレIDが9桁の場合 → http://サーバ/板ID/kako/IDの上位3桁/ID.dat.gz
+ (3) 過去ログ倉庫から読み込み (※2)
+ ・スレIDが10桁の場合 → http://サーバ/板ID/kako/IDの上位4桁/IDの上位5桁/ID.dat
+ ・スレIDが9桁の場合 → http://サーバ/板ID/kako/IDの上位3桁/ID.dat
+ (4) 外部のログ保存サービスから読み込み
+ (5) read.cgiで読み込んでない場合にはread.cgiからの読み込み
- ・スレIDが9桁の場合 → http://サーバ/板ID/kako/IDの上位3桁/ID.dat.gz
+ (※1)ただし 2008年1月1日以降に立てられたスレは除く
+ (※2)少なくても rokka導入(2013年9月27日)以降に立てられたスレ除く
- (例) http://HOGE.2ch.net/test/read.cgi/hoge/123456789/ を取得
-
- (1) http://HOGE.2ch.net/hoge/dat/1234567890.dat から dat を取得。302で●がある場合(2-1)、旧URLがある場合(2-2)、無い場合は(2-3)へ(※)
-
- (2-1) offlaw.cgiを使って取得
-
- (2-2) 旧URLから取得
-
- (2-3) http://HOGE.2ch.net/hoge/kako/123/123456789.dat.gz から取得。302なら(3)へ
-
- (3) http://HOGE.2ch.net/hoge/kako/123/123456789.dat から取得
-
-
- (※)ただし 2008年1月1日以降に立てられたスレは除く
-
- (注) 古すぎる(2000年頃)のdatは形式が違う(<>ではなくて,で区切られている)ので読み込みに失敗する
+ (注) 古すぎる(2000年頃)のdatは形式が違う(<>ではなくて,で区切られている)ので読み込みに考慮が必要
*/
- // ログインしている場合は rokka 経由で旧URLで再取得
- if( m_mode == MODE_NORMAL && CORE::get_login2ch()->login_now() ) m_mode = MODE_OFFLAW;
-
- // offlaw2.so 経由で再取得 ( bbspink を除く )
- else if( m_mode == MODE_NORMAL && CONFIG::get_use_offlaw2_2ch()
- && get_url().find( ".bbspink.com" ) == std::string::npos ) m_mode = MODE_OFFLAW2;
-
// 旧URLがある場合、そのURLで再取得
- else if( ( m_mode == MODE_NORMAL || m_mode == MODE_OFFLAW || m_mode == MODE_OFFLAW2 ) && get_url() != m_org_url ) m_mode = MODE_OLDURL;
+ if( m_mode == MODE_NORMAL && get_url() != m_org_url ) m_mode = MODE_OLDURL;
// 過去ログ倉庫(gz圧縮)
- // ただし 2008年1月1日以降に立てられたスレは除く
- else if( ( m_mode == MODE_NORMAL || m_mode == MODE_OFFLAW || m_mode == MODE_OLDURL ) && m_since_time < 1199113200 ) m_mode = MODE_KAKO_GZ;
+ else if( m_mode <= MODE_OLDURL && m_since_time < 1380246829 ){
+ // ただし 2008年1月1日以降に立てられたスレは除く
+ if( m_since_time < 1199113200 ) m_mode = MODE_KAKO_GZ;
+ else if( m_mode != MODE_OLDURL ) m_mode = MODE_KAKO;
+ }
// 過去ログ倉庫
else if( m_mode == MODE_KAKO_GZ ) m_mode = MODE_KAKO;
+ // 外部のログ保存サービス
+ else if( m_mode != MODE_KAKO_EXT && CONFIG::get_use_external_log() ) m_mode = MODE_KAKO_EXT;
+
// 失敗
else m_mode = MODE_NORMAL;
-#ifdef _DEBUG
- std::cout << "switch mode to " << m_mode << std::endl;
-#endif
if( m_mode != MODE_NORMAL ){
- download_dat( is_checking_update() );
+#ifdef _DEBUG
+ std::cout << "switch mode to " << m_mode << std::endl;
+#endif
+ set_date_modified( std::string() );
+ set_ext_err( std::string() );
+ download_dat( false );
return;
}
+
+ // プールしていたレスを追加
+ if( ! m_operate_info.empty() ){
+ NodeTreeBase::receive_data( m_operate_info.c_str(), m_operate_info.length() );
+ }
}
- // offlaw や 過去ログから読み込んだ場合は DAT 落ちにする
- if( m_mode != MODE_NORMAL ){
- m_mode = MODE_NORMAL;
+ m_operate_info = std::string();
+
+ // 過去ログから読み込んだ場合は DAT 落ちにする
+ if( m_mode >= MODE_KAKO_GZ ){
set_code( HTTP_OLD );
}
NodeTreeBase::receive_finish();
+ m_mode = MODE_NORMAL;
}
diff --git a/src/dbtree/nodetree2ch.h b/src/dbtree/nodetree2ch.h
index ba0c6ddd..28f05652 100644
--- a/src/dbtree/nodetree2ch.h
+++ b/src/dbtree/nodetree2ch.h
@@ -17,6 +17,9 @@ namespace DBTREE
std::string m_org_url; // 移転前のオリジナルURL
time_t m_since_time; // スレが立った時刻
int m_mode; // 読み込みモード
+ int m_res_number_max; // 最大レス数
+
+ std::string m_operate_info;
public:
@@ -24,12 +27,16 @@ namespace DBTREE
const std::string& date_modified, time_t since_time );
~NodeTree2ch();
+ int get_res_number_max() override { return m_res_number_max; }
+
protected:
- char* process_raw_lines( char* rawlines ) override;
+ char* process_raw_lines( char* rawlines, size_t& size ) override;
void create_loaderdata( JDLIB::LOADERDATA& data ) override;
+ void parse_extattr( const char* str, const int lng ) override;
+
private:
void receive_finish() override;
diff --git a/src/dbtree/nodetree2chcompati.cpp b/src/dbtree/nodetree2chcompati.cpp
index 6e093d8d..4fb37d14 100644
--- a/src/dbtree/nodetree2chcompati.cpp
+++ b/src/dbtree/nodetree2chcompati.cpp
@@ -33,7 +33,8 @@ NodeTree2chCompati::~NodeTree2chCompati()
std::cout << "NodeTree2chCompati::~NodeTree2chCompati : " << get_url() << std::endl;
#endif
- clear();
+ // iconv 削除
+ if( m_iconv ) delete m_iconv;
}
@@ -68,67 +69,11 @@ void NodeTree2chCompati::init_loading()
NodeTreeBase::init_loading();
// iconv 初期化
- std::string charset = DBTREE::board_charset( get_url() );
- if( ! m_iconv ) m_iconv = new JDLIB::Iconv( charset, "UTF-8" );
+ if( ! m_iconv ) m_iconv = new JDLIB::Iconv( DBTREE::article_charcode( get_url() ), CHARCODE_UTF8 );
}
-//
-// キャッシュに保存する前の前処理
-//
-// 先頭にrawモードのステータスが入っていたら取り除く
-//
-char* NodeTree2chCompati::process_raw_lines( char* rawlines )
-{
- char* pos = rawlines;
-
- if( *pos == '+' || *pos == '-' || *pos == 'E' ){
-
- int status = 0;
- if( pos[ 1 ] == 'O' && pos[ 2 ] == 'K' ) status = 1;
- if( pos[ 1 ] == 'E' && pos[ 2 ] == 'R' && pos[ 3 ] == 'R' ) status = 2;
- if( pos[ 1 ] == 'I' && pos[ 2 ] == 'N' && pos[ 3 ] == 'C' && pos[ 4 ] == 'R' ) status = 3;
- if( pos[ 0 ] == 'E' && pos[ 1 ] == 'R' && pos[ 2 ] == 'R' && pos[ 3 ] == 'O' && pos[ 4 ] == 'R' ) status = 4;
-
-#ifdef _DEBUG
- std::cout << "NodeTree2chCompati::process_raw_lines : raw mode status = " << status << std::endl;
-#endif
-
- if( status != 0 ){
- pos = skip_status_line( pos, status );
- }
- }
-
- return pos;
-}
-
-
-//
-// ステータス行のスキップ処理
-// status == 1 : 正常ステータス
-// status != 1 : 異常ステータス
-//
-char* NodeTree2chCompati::skip_status_line( char* pos, int status )
-{
- // この行を飛ばす
- char* pos_msg = pos;
- while( *pos != '\n' && *pos != '\0' ) ++pos;
-
- // エラー
- if( status != 1 ){
- int byte;
- std::string ext_err = std::string( m_iconv->convert( pos_msg, pos - pos_msg, byte ) );
- set_ext_err( ext_err );
- MISC::ERRMSG( ext_err );
- }
-
- if( *pos == '\n' ) ++pos;
-
- return pos;
-}
-
-
//
// raw データを dat 形式に変換
//
diff --git a/src/dbtree/nodetree2chcompati.h b/src/dbtree/nodetree2chcompati.h
index f819411e..9630c2a7 100644
--- a/src/dbtree/nodetree2chcompati.h
+++ b/src/dbtree/nodetree2chcompati.h
@@ -29,11 +29,8 @@ namespace DBTREE
void clear() override;
void init_loading() override;
- char* process_raw_lines( char* rawlines ) override;
const char* raw2dat( char* rawlines, int& byte ) override;
- char* skip_status_line( char* pos, int status );
-
void create_loaderdata( JDLIB::LOADERDATA& data ) override;
};
}
diff --git a/src/dbtree/nodetreebase.cpp b/src/dbtree/nodetreebase.cpp
index 5ea20d19..05bad4f8 100644
--- a/src/dbtree/nodetreebase.cpp
+++ b/src/dbtree/nodetreebase.cpp
@@ -7,10 +7,11 @@
#include "spchar_decoder.h"
#include "interface.h"
-#include "jdlib/miscutil.h"
+#include "jdlib/misccharcode.h"
+#include "jdlib/miscgtk.h"
#include "jdlib/miscmsg.h"
+#include "jdlib/misctrip.h"
#include "jdlib/loaderdata.h"
-#include "jdlib/jdregex.h"
#include "dbimg/imginterface.h"
@@ -25,7 +26,9 @@
#include "command.h"
#include "cache.h"
#include "session.h"
+#include "replacestrmanager.h"
#include "urlreplacemanager.h"
+#include "cssmanager.h"
#include <sstream>
#include <fstream>
@@ -50,10 +53,11 @@ constexpr size_t MAX_ANCINFO = 64;
constexpr int RANGE_REF = 20;
constexpr size_t MAX_RES_DIGIT = std::numeric_limits< int >::digits10 + 1; // レスアンカーや発言数で使われるレスの桁数
-constexpr size_t MAXSISE_OF_LINES = 512 * 1024; // ロード時に1回の呼び出しで読み込まれる最大データサイズ
-constexpr size_t SIZE_OF_HEAP = MAXSISE_OF_LINES + 64;
+constexpr size_t MAXSISE_OF_LINES = 256 * 1024; // ロード時に1回の呼び出しで読み込まれる最大データサイズ
+constexpr size_t SIZE_OF_HEAP = 512 * 1024;
constexpr size_t INITIAL_RES_BUFSIZE = 128; // レスの文字列を返すときの初期バッファサイズ
+constexpr size_t IDHASH_TBLSIZE = 1024; // IDのハッシュテーブルサイズ
// レジュームのモード
@@ -68,11 +72,9 @@ enum
#define IS_URL(node) \
-( node->type == NODE_LINK && node->linkinfo->link \
-&& ( std::string( node->linkinfo->link ).find( "http" ) == 0 \
-|| std::string( node->linkinfo->link ).find( "https" ) == 0 \
-|| std::string( node->linkinfo->link ).find( "ftp" ) == 0 ) \
-)
+ ( node->type == NODE_LINK && node->linkinfo->link \
+ && ( memcmp( node->linkinfo->link, "http", 4 ) == 0 \
+ || memcmp( node->linkinfo->link, "ftp", 3 ) == 0 ) )
using namespace DBTREE;
@@ -87,12 +89,14 @@ NodeTreeBase::NodeTreeBase( const std::string& url, const std::string& modified
m_broken( false ),
m_heap( SIZE_OF_HEAP ),
m_buffer_lines( NULL ),
+ m_byte_buffer_lines_left( 0 ),
m_parsed_text( NULL ),
m_buffer_write( NULL ),
m_check_update( false ),
m_check_write( false ),
m_loading_newthread( false ),
- m_fout ( NULL )
+ m_fout ( NULL ),
+ m_idhash( NULL )
{
set_date_modified( modified );
@@ -105,6 +109,7 @@ NodeTreeBase::NodeTreeBase( const std::string& url, const std::string& modified
assert( m_vec_header.size() == static_cast< decltype( m_vec_header.size() ) >( m_id_header ) );
m_vec_header.push_back( tmpnode );
+ m_url_readcgi = url_readcgi( m_url, 0, 0 );
m_default_noname = DBTREE::default_noname( m_url );
// 参照で色を変える回数
@@ -117,9 +122,9 @@ NodeTreeBase::NodeTreeBase( const std::string& url, const std::string& modified
// レスにアスキーアートがあると判定する正規表現
if( CONFIG::get_aafont_enabled() ){
- m_aa_regex = CONFIG::get_regex_res_aa();
- } else {
- m_aa_regex = std::string();
+ const bool icase = false;
+ const bool newline = true;
+ m_aa_regex.set( CONFIG::get_regex_res_aa(), icase, newline );
}
#ifdef _DEBUG
@@ -159,6 +164,7 @@ void NodeTreeBase::update_url( const std::string& url )
#endif
m_url = url;
+ m_url_readcgi = url_readcgi( m_url, 0, 0 );
#ifdef _DEBUG
if( ! old_url.empty() ) std::cout << "NodeTreeBase::update_url from " << old_url
@@ -237,10 +243,17 @@ int NodeTreeBase::get_num_id_name( const std::string& id )
}
// IDの数を数えている場合
-
- for( int i = 1; i <= m_id_header; ++i ){
-
- if( get_id_name( i ) == id ) return get_num_id_name( i );
+ if( m_idhash ){
+ int key = MISC::fnv_hash( id.c_str(), id.length() ) % IDHASH_TBLSIZE;
+ IDHASH* idhash = m_idhash[ key ];
+ if( idhash ){
+ while( true ){
+ const int cmp = strcmp( id.c_str(), idhash->id );
+ if( cmp == 0 ) return get_num_id_name( idhash->num );
+ if( ! idhash->child[ cmp>0 ] ) break;
+ idhash = idhash->child[ cmp>0 ];
+ }
+ }
}
return 0;
@@ -384,7 +397,7 @@ std::list< int > NodeTreeBase::get_res_with_url()
//
// 含まれる URL をリストにして取得
//
-std::list< std::string > NodeTreeBase::get_urls()
+const std::list< std::string > NodeTreeBase::get_imglinks()
{
std::list< std::string > list_urls;
for( int i = 1; i <= m_id_header; ++i ){
@@ -397,7 +410,8 @@ std::list< std::string > NodeTreeBase::get_urls()
NODE* node = head->headinfo->block[ block ];
while( node ){
- if( IS_URL( node ) ) list_urls.push_back( node->linkinfo->link );
+ if( IS_URL( node ) && node->linkinfo->imglink )
+ list_urls.push_back( node->linkinfo->imglink );
node = node->next_node;
}
}
@@ -552,21 +566,21 @@ std::list< int > NodeTreeBase::get_res_query( const std::string& query, const bo
std::list< int > list_resnum;
if( query.empty() ) return list_resnum;
- std::list< JDLIB::Regex > list_regex;
+ std::list< JDLIB::RegexPattern > list_regex;
+ JDLIB::Regex regex;
const size_t offset = 0;
const bool icase = true; // 大文字小文字区別しない
const bool newline = true; // . に改行をマッチさせない
const bool usemigemo = true; // migemo使用
- const bool wchar = true; // 全角半角の区別をしない
+ const bool wchar = false; // 全角半角の区別をしない
+ const bool norm = true; // Unicodeの互換文字を区別しない
const std::list< std::string > list_query = MISC::split_line( query );
std::list< std::string >::const_iterator it_query;
for( it_query = list_query.begin(); it_query != list_query.end() ; ++it_query ){
- const std::string &query = ( *it_query );
-
- list_regex.push_back( JDLIB::Regex() );
- list_regex.back().compile( query, icase, newline, usemigemo, wchar );
+ list_regex.push_back( JDLIB::RegexPattern() );
+ list_regex.back().set( *it_query, icase, newline, usemigemo, wchar, norm );
}
for( int i = 1; i <= m_id_header ; ++i ){
@@ -576,11 +590,9 @@ std::list< int > NodeTreeBase::get_res_query( const std::string& query, const bo
bool apnd = true;
if( mode_or ) apnd = false;
- std::list< JDLIB::Regex >::iterator it_regex;
- for( it_regex = list_regex.begin(); it_regex != list_regex.end() ; ++it_regex ){
+ for( const JDLIB::RegexPattern& pattern : list_regex ) {
- JDLIB::Regex &regex = ( *it_regex );
- const bool ret = regex.exec( res_str, offset );
+ const bool ret = regex.match( pattern, res_str, offset );
// OR
if( mode_or ){
@@ -621,6 +633,7 @@ std::list< int > NodeTreeBase::get_res_query( const std::string& query, const bo
node = head->headinfo->block[ id ]; \
while( node ){ \
if( node->type == DBTREE::NODE_BR ) str_res += "\n" + ref_prefix; \
+else if( node->type == DBTREE::NODE_SP ) str_res += " "; \
else if( node->type == DBTREE::NODE_HTAB ) str_res += "\t"; \
else if( node->text ) str_res += node->text; \
node = node->next_node; \
@@ -664,53 +677,6 @@ std::string NodeTreeBase::get_res_str( int number, bool ref )
-//
-// number 番のレスの生文字列を返す
-//
-std::string NodeTreeBase::get_raw_res_str( int number )
-{
-#ifdef _DEBUG
- std::cout << "NodeTreeBase::get_raw_res_str : num = " << number << std::endl;
-#endif
- std::string retstr;
-
- std::string str;
- std::string path_cache = CACHE::path_dat( m_url );
- if( ! CACHE::load_rawdata( path_cache, str ) ) return std::string();
-
- char* rawlines = ( char* ) malloc( str.size() + 64 );
- strcpy( rawlines, str.c_str() );
-
- // dat形式に変換
-
- int id_header = m_id_header;
- m_id_header = 0;
- init_loading();
-
- int byte;
- const char* datlines = raw2dat( rawlines, byte );
- if( byte ){
-
- std::list< std::string > lines = MISC::get_lines( datlines );
- std::list< std::string >::iterator it = lines.begin();
- for( int i = 1; it != lines.end() && i < number ; ++it, ++i );
- if( it != lines.end() ) retstr = *it;
- }
-
-#ifdef _DEBUG
- std::cout << retstr << std::endl;
-#endif
-
- clear();
- m_id_header = id_header;
- if( rawlines ) free( rawlines );
-
- return retstr;
-}
-
-
-
-
//
// number番を書いた人の名前を取得
//
@@ -789,10 +755,17 @@ std::string NodeTreeBase::get_time_str( int number )
std::string NodeTreeBase::get_id_name( int number )
{
NODE* head = res_header( number );
- if( ! head ) return std::string();
- if( ! head->headinfo->block[ BLOCK_ID_NAME ] ) return std::string();
+ if( ! head || ! head->headinfo->block[ BLOCK_ID_NAME ] ) return std::string();
- return head->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link;
+ NODE* idnode = head->headinfo->block[ BLOCK_ID_NAME ]->next_node;
+ while( idnode && ( ! idnode->linkinfo || ! idnode->linkinfo->link
+ || idnode->linkinfo->link[ 0 ] != 'I' ) ){
+ idnode = idnode->next_node;
+ }
+
+ if( idnode ) return idnode->linkinfo->link;
+
+ return std::string();
}
@@ -872,7 +845,8 @@ NODE* NodeTreeBase::create_node_idnum()
//
NODE* NodeTreeBase::create_node_br()
{
- NODE* tmpnode = create_node();
+ // 改行前の空白を取り除く
+ NODE* tmpnode = ( m_node_previous->type == NODE_SP ) ? m_node_previous : create_node();
tmpnode->type = NODE_BR;
return tmpnode;
}
@@ -892,10 +866,23 @@ NODE* NodeTreeBase::create_node_hr()
//
// スペースノード
//
-NODE* NodeTreeBase::create_node_space( const int type )
+NODE* NodeTreeBase::create_node_space( const int type, const int bg )
{
- NODE* tmpnode = create_node();
- tmpnode->type = type;
+ NODE* tmpnode;
+
+ if( type != NODE_SP ||
+ ( m_node_previous->type != type && m_node_previous->type != NODE_MULTISP
+ && m_node_previous->type != NODE_HTAB ) ){
+ tmpnode = create_node();
+ tmpnode->type = type;
+ tmpnode->color_text = COLOR_CHAR;
+ tmpnode->color_back = bg;
+ tmpnode->bold = false;
+ }
+ else{
+ tmpnode = m_node_previous;
+ }
+
return tmpnode;
}
@@ -903,39 +890,28 @@ NODE* NodeTreeBase::create_node_space( const int type )
//
// 連続半角スペース
//
-NODE* NodeTreeBase::create_node_multispace( const char* text, const int n )
+NODE* NodeTreeBase::create_node_multispace( const char* text, const int n, const int bg )
{
- NODE* tmpnode = create_node_ntext( text, n, COLOR_CHAR, false );
+ NODE* tmpnode = create_node_ntext( text, n, COLOR_CHAR, bg, false );
tmpnode->type = NODE_MULTISP;
return tmpnode;
}
-//
-// 水平タブノード
-//
-NODE* NodeTreeBase::create_node_htab()
-{
- NODE* tmpnode = create_node();
- tmpnode->type = NODE_HTAB;
- return tmpnode;
-}
-
-
//
// リンクノード作成
//
// bold : 太字か
//
-NODE* NodeTreeBase::create_node_link( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold )
+NODE* NodeTreeBase::create_node_link( const char* text, const int n, const char* link, const int n_link, const int color_text, const int color_back, const bool bold )
{
- NODE* tmpnode = create_node_ntext( text, n, color_text, bold );
+ NODE* tmpnode = create_node_ntext( text, n, color_text, color_back, bold );
if( tmpnode ){
tmpnode->type = NODE_LINK;
// リンク情報作成
- char *tmplink = ( char* )m_heap.heap_alloc( n_link +4 );
+ char *tmplink = ( char* )m_heap.heap_alloc( n_link + 1 );
memcpy( tmplink, link, n_link );
tmplink[ n_link ] = '\0';
@@ -955,7 +931,7 @@ NODE* NodeTreeBase::create_node_anc( const char* text, const int n, const char*
const int color_text, const bool bold,
const ANCINFO* ancinfo, const int lng_ancinfo )
{
- NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, bold );
+ NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, COLOR_NONE, bold );
if( tmpnode ){
tmpnode->linkinfo->ancinfo = ( ANCINFO* )m_heap.heap_alloc( sizeof( ANCINFO ) * ( lng_ancinfo + 1 ) );
@@ -975,7 +951,7 @@ NODE* NodeTreeBase::create_node_sssp( const char* link, const int n_link )
tmpnode->type = NODE_SSSP;
// リンク情報作成
- char *tmplink = ( char* )m_heap.heap_alloc( n_link +4 );
+ char *tmplink = ( char* )m_heap.heap_alloc( n_link + 1 );
memcpy( tmplink, link, n_link );
tmplink[ n_link ] = '\0';
@@ -994,7 +970,7 @@ NODE* NodeTreeBase::create_node_sssp( const char* link, const int n_link )
//
NODE* NodeTreeBase::create_node_img( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold )
{
- NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, bold );
+ NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, COLOR_NONE, bold );
if( tmpnode ){
tmpnode->linkinfo->image = true;
tmpnode->linkinfo->imglink = tmpnode->linkinfo->link;
@@ -1009,11 +985,11 @@ NODE* NodeTreeBase::create_node_img( const char* text, const int n, const char*
//
NODE* NodeTreeBase::create_node_thumbnail( const char* text, const int n, const char* link, const int n_link, const char* thumb, const int n_thumb, const int color_text, const bool bold )
{
- NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, bold );
+ NODE* tmpnode = create_node_link( text, n, link, n_link, color_text, COLOR_NONE, bold );
if( tmpnode ){
// サムネイル画像のURLをセット
- char *tmpthumb = ( char* )m_heap.heap_alloc( n_thumb +4 );
+ char *tmpthumb = ( char* )m_heap.heap_alloc( n_thumb + 1 );
memcpy( tmpthumb, thumb, n_thumb );
tmpthumb[ n_thumb ] = '\0';
@@ -1030,7 +1006,7 @@ NODE* NodeTreeBase::create_node_thumbnail( const char* text, const int n, const
//
NODE* NodeTreeBase::create_node_text( const char* text, const int color_text, const bool bold )
{
- return create_node_ntext( text, strlen( text ), color_text, bold );
+ return create_node_ntext( text, strlen( text ), color_text, COLOR_NONE, bold );
}
@@ -1038,7 +1014,7 @@ NODE* NodeTreeBase::create_node_text( const char* text, const int color_text, co
//
// テキストノード作成( サイズ指定 )
//
-NODE* NodeTreeBase::create_node_ntext( const char* text, const int n, const int color_text, const bool bold )
+NODE* NodeTreeBase::create_node_ntext( const char* text, const int n, const int color_text, const int color_back, const bool bold )
{
if( n <= 0 ) return NULL;
@@ -1050,6 +1026,7 @@ NODE* NodeTreeBase::create_node_ntext( const char* text, const int n, const int
tmpnode->text = ( char* )m_heap.heap_alloc( n + MAX_RES_DIGIT + 4 );
memcpy( tmpnode->text, text, n ); tmpnode->text[ n ] = '\0';
tmpnode->color_text = color_text;
+ tmpnode->color_back = color_back;
tmpnode->bold = bold;
}
@@ -1126,19 +1103,16 @@ void NodeTreeBase::load_cache()
std::string str;
if( CACHE::load_rawdata( path_cache, str ) ){
- const char* data = str.data();
- size_t size = 0;
m_check_update = false;
m_check_write = false;
m_loading_newthread = false;
set_resume( false );
init_loading();
+
+ const char* data = str.data();
const size_t str_length = str.length();
- while( size < str_length ){
- size_t size_tmp = MIN( MAXSISE_OF_LINES - m_byte_buffer_lines_left, str_length - size );
- receive_data( data + size, size_tmp );
- size += size_tmp;
- }
+
+ receive_data( data, str_length );
receive_finish();
// レジューム時のチェックデータをキャッシュ
@@ -1159,7 +1133,7 @@ void NodeTreeBase::set_resume_data( const char* data, size_t length )
// レジューム時のチェック用に生データの先頭から RESUME_CHKSIZE バイト分をコピーしておく
// 詳しくは NodeTreeBase::receive_data() を参照せよ
- const size_t length_chk = MIN( RESUME_CHKSIZE, length );
+ const size_t length_chk = MIN( (RESUME_CHKSIZE - 1), length );
memcpy( m_resume_head, data, length_chk );
m_resume_head[ length_chk ] = '\0';
}
@@ -1171,8 +1145,6 @@ void NodeTreeBase::set_resume_data( const char* data, size_t length )
//
void NodeTreeBase::init_loading()
{
- clear();
-
// 一時バッファ作成
if( ! m_buffer_lines ) m_buffer_lines = ( char* ) malloc( MAXSISE_OF_LINES );
if( ! m_parsed_text ) m_parsed_text = ( char* ) malloc( MAXSISE_OF_LINES );
@@ -1261,6 +1233,7 @@ void NodeTreeBase::download_dat( const bool check_update )
if( m_check_update ){
data.head = true;
data.timeout = CONFIG::get_loader_timeout_checkupdate();
+ if( data.byte_readfrom ) data.byte_readfrom += 1;
}
if( data.url.empty() || ! start_load( data ) ){
@@ -1275,8 +1248,6 @@ void NodeTreeBase::download_dat( const bool check_update )
//
void NodeTreeBase::receive_data( const char* data, size_t size )
{
- // BOF防止
- size = MIN( MAXSISE_OF_LINES, size );
if( is_loading()
&& ( get_code() != HTTP_OK && get_code() != HTTP_PARTIAL_CONTENT ) ){
@@ -1326,33 +1297,61 @@ void NodeTreeBase::receive_data( const char* data, size_t size )
if( !size ) return;
- // バッファが '\n' で終わるように調整
- const char* pos = data + size;
- if( *pos == '\n' && pos != data ) --pos;
- if( *pos == '\0' ) --pos; // '\0' を除く
- while( *pos != '\n' && pos != data ) --pos;
+ while( size > 0 ){
- // 前回の残りのデータに新しいデータを付け足して add_raw_lines()にデータを送る
- size_t size_in = ( int )( pos - data );
- if( size_in > 0 ){
- size_in ++; // '\n'を加える
- memcpy( m_buffer_lines + m_byte_buffer_lines_left , data, size_in );
- m_buffer_lines[ m_byte_buffer_lines_left + size_in ] = '\0';
- add_raw_lines( m_buffer_lines, m_byte_buffer_lines_left + size_in );
- }
+ // BOF防止
+ size_t size_in = MIN( MAXSISE_OF_LINES - m_byte_buffer_lines_left - 1, size );
- // add_raw_lines() でレジュームに失敗したと判断したら、バッファをクリアする
- if( m_resume == RESUME_FAILED ){
- m_byte_buffer_lines_left = 0;
- return;
+ // バッファが '\n' で終わるように調整
+ const char* pos = data + size_in;
+ while( pos != data && *(pos - 1) != '\n' ) --pos;
+
+ if( pos != data ) size_in = pos - data;
+ // バッファサイズの半分までは改行を待ってみる
+ else if( ( m_byte_buffer_lines_left + size ) < ( MAXSISE_OF_LINES / 2 ) ) size_in = 0;
+
+ if( size_in > 0 ){
+ // 前回の残りのデータに新しいデータを付け足して add_raw_lines()にデータを送る
+ memcpy( m_buffer_lines + m_byte_buffer_lines_left, data, size_in );
+ m_buffer_lines[ m_byte_buffer_lines_left + size_in ] = '\0';
+ size_t lng = add_raw_lines( m_buffer_lines, m_byte_buffer_lines_left + size_in );
+ m_byte_buffer_lines_left = m_byte_buffer_lines_left + size_in - lng;
+ memmove( m_buffer_lines, m_buffer_lines + lng, m_byte_buffer_lines_left );
+ data += size_in;
+ size -= size_in;
+ }
+ else break;
+
+ // add_raw_lines() でレジュームに失敗したと判断したら、バッファをクリアする
+ if( m_resume == RESUME_FAILED ){
+ m_byte_buffer_lines_left = 0;
+ return;
+ }
}
// 残りの分をバッファにコピーしておく
- m_byte_buffer_lines_left = size - size_in;
- if( m_byte_buffer_lines_left ) memcpy( m_buffer_lines, data + size_in, m_byte_buffer_lines_left );
+ if( size > 0 ){
+ memcpy( m_buffer_lines + m_byte_buffer_lines_left, data, size );
+ m_byte_buffer_lines_left += size;
+ }
}
+//
+// 保留された受信データのはき出し
+//
+void NodeTreeBase::sweep_buffer()
+{
+ // 特殊スレのdatには、最後の行に'\n'がない場合がある
+ if( m_byte_buffer_lines_left > 0 ){
+ // 正常に読込完了した場合で、バッファが残っていれば add_raw_lines()にデータを送る
+ m_buffer_lines[ m_byte_buffer_lines_left ] = '\0';
+ add_raw_lines( m_buffer_lines, m_byte_buffer_lines_left );
+ // バッファをクリア
+ m_byte_buffer_lines_left = 0;
+ }
+}
+
//
// ロード完了
@@ -1364,6 +1363,7 @@ void NodeTreeBase::receive_finish()
&& get_code() != HTTP_OK
&& get_code() != HTTP_PARTIAL_CONTENT
&& get_code() != HTTP_NOT_MODIFIED
+ && get_code() != HTTP_RANGE_ERR
&& get_code() != HTTP_OLD
){
is_error = true;
@@ -1371,26 +1371,19 @@ void NodeTreeBase::receive_finish()
std::ostringstream err;
err << m_url << std::endl
<< "load failed. : " << get_str_code();
- if( get_code() == HTTP_REDIRECT || get_code() == HTTP_REDIRECT ) err << " location = " << location();
+ if( get_code() == HTTP_MOVED_PERM || get_code() == HTTP_REDIRECT ) err << " location = " << location();
MISC::ERRMSG( err.str() );
}
- if( ! m_check_update ){
+ // 保留データの処理
+ if( ! is_error ) sweep_buffer();
+ else m_byte_buffer_lines_left = 0;
- if( ! is_error ){
- // 特殊スレのdatには、最後の行に'\n'がない場合がある
- if( m_byte_buffer_lines_left > 0 ){
- // 正常に読込完了した場合で、バッファが残っていれば add_raw_lines()にデータを送る
- m_buffer_lines[ m_byte_buffer_lines_left ] = '\0';
- add_raw_lines( m_buffer_lines, m_byte_buffer_lines_left );
- // バッファをクリア
- m_byte_buffer_lines_left = 0;
- }
- }
+ if( ! m_check_update ){
// Requested Range Not Satisfiable
if( get_code() == HTTP_RANGE_ERR ){
- m_broken = true;
+// m_broken = true;
MISC::ERRMSG( "Requested Range Not Satisfiable" );
}
@@ -1428,7 +1421,14 @@ void NodeTreeBase::receive_finish()
if( ! m_check_update
&& ( get_code() == HTTP_OK || get_code() == HTTP_PARTIAL_CONTENT )
- && ! get_date_modified().empty() ) CACHE::set_filemtime( CACHE::path_dat( m_url ), get_time_modified() );
+ && ! get_date_modified().empty() ){
+
+ CACHE::set_filemtime( CACHE::path_dat( m_url ), get_time_modified() );
+
+ // クッキーのセット
+ const::std::list< std::string > list_cookies = SKELETON::Loadable::cookies();
+ DBTREE::board_set_list_cookies_for_write( m_url, list_cookies );
+ }
m_check_update = false;
m_check_write = false;
@@ -1439,22 +1439,24 @@ void NodeTreeBase::receive_finish()
//
// 鯖から生の(複数)行のデータを受け取ってdat形式に変換して add_one_dat_line() に出力
//
-void NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
+size_t NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
{
// 時々サーバ側のdatファイルが壊れていてデータ中に \0 が
// 入っている時があるので取り除く
for( size_t i = 0; i < size; ++i ){
if( rawlines[ i ] == '\0' ){
- MISC::ERRMSG( "EOF was inserted in the middle of the raw data" );
- rawlines[ i ] = ' ';
+ size_t beg = i;
+ while( i < size && rawlines[ i ] == '\0' ) ++i;
+ MISC::ERRMSG( MISC::itostr( i - beg ) + " EOF was inserted in the middle of the raw data" );
+ memset( rawlines + beg, ' ', i - beg );
}
}
// 保存前にrawデータを加工
- rawlines = process_raw_lines( rawlines );
+ rawlines = process_raw_lines( rawlines, size );
size_t lng = strlen( rawlines );
- if( ! lng ) return;
+ if( ! lng ) return size;
// サーバが range を無視してデータを送ってきたときのレジューム処理
if( m_resume == RESUME_MODE2 ){
@@ -1464,7 +1466,7 @@ void NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
#endif
// 先頭からdatを送ってきたかチェック
- const size_t length_chk = MIN( lng, MIN( RESUME_CHKSIZE, strlen( m_resume_head ) ) );
+ const size_t length_chk = MIN( lng, MIN( (RESUME_CHKSIZE - 1), strlen( m_resume_head ) ) );
if( strncmp( rawlines, m_resume_head, length_chk ) == 0 ){
m_resume = RESUME_MODE3;
m_resume_lng = 0;
@@ -1476,7 +1478,7 @@ void NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
m_broken = true;
MISC::ERRMSG( "failed to resume" );
m_resume = RESUME_FAILED;
- return;
+ return size;
}
}
@@ -1489,7 +1491,7 @@ void NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
#endif
m_resume_lng += lng;
- if( m_resume_lng <= m_lng_dat ) return;
+ if( m_resume_lng <= m_lng_dat ) return size;
// 越えた分をカットしてレジューム処理終了
rawlines += ( lng - ( m_resume_lng - m_lng_dat ) );
@@ -1501,7 +1503,7 @@ void NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
#endif
}
- if( ! lng ) return;
+ if( ! lng ) return size;
m_lng_dat += lng;
@@ -1520,7 +1522,7 @@ void NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
// dat形式に変換
int byte;
const char* datlines = raw2dat( rawlines, byte );
- if( !byte ) return;
+ if( !byte ) return size;
// '\n' 単位で区切って add_one_dat_line() に渡す
int num_before = m_id_header;
@@ -1545,6 +1547,7 @@ void NodeTreeBase::add_raw_lines( char* rawlines, size_t size )
// articlebase クラスに状態が変わったことを知らせる
m_sig_updated.emit();
}
+ return size;
}
@@ -1576,7 +1579,7 @@ const char* NodeTreeBase::add_one_dat_line( const char* datline )
snprintf( tmplink, LNG_RES,"%s%d", PROTO_RES, header->id_header );
header->headinfo->block[ BLOCK_NUMBER ] = create_node_block();
- create_node_link( tmpstr, strlen( tmpstr ) , tmplink, strlen( tmplink ), COLOR_CHAR_LINK_RES, true );
+ create_node_link( tmpstr, strlen( tmpstr ) , tmplink, strlen( tmplink ), COLOR_CHAR_LINK_RES, COLOR_NONE, true );
const char* section[ SECTION_NUM ];
int section_lng[ SECTION_NUM ];
@@ -1585,14 +1588,66 @@ const char* NodeTreeBase::add_one_dat_line( const char* datline )
for( i = 0; i < SECTION_NUM ; ++i ){
section[ i ] = pos;
- while( !( *pos == '<' && *( pos + 1 ) == '>' ) && ( *pos != '\0' && *pos != '\n' ) ) ++pos;
- section_lng[ i ] = ( int )( pos - section[ i ] );
+ while( *pos != '\0' && *pos != '\n' && !( *pos == '<' && *( pos + 1 ) == '>' ) ) ++pos;
+ section_lng[ i ] = pos - section[ i ];
- if( ( *pos == '\0' || *pos == '\n' ) && i < SECTION_NUM -1 ) break; // 壊れてる
-
- if ( !( *pos == '\0' || *pos == '\n' ) ) pos += 2; // "<>"の分
+ if( *pos == '\0' || *pos == '\n' ){ ++i; break; }
+ else pos += 2; // "<>"の分
}
+ if( i < ( SECTION_NUM - 1) ){
+ // 本文途中まで解析出来てなければ旧dat形式でチェックしてみる
+ pos = datline;
+
+ for( i = 0; i < SECTION_NUM ; ++i ){
+
+ section[ i ] = pos;
+ while( *pos != ',' && *pos != '\0' && *pos != '\n' ) ++pos;
+ section_lng[ i ] = pos - section[ i ];
+
+ if( *pos == '\0' || *pos == '\n' ){ ++i; break; }
+ else pos += 1; // ","の分
+ }
+ }
+
+ // 行末まで読み飛ばす
+ while( *pos != '\0' && *pos != '\n' ) ++pos;
+
+ // 名前
+ int color_name = COLOR_CHAR_NAME;
+ if( ! section_lng[ 1 ] ) color_name = COLOR_CHAR_NAME_NOMAIL;
+ parse_name( header, section[ 0 ], section_lng[ 0 ], color_name );
+
+ // メール
+ if( i > 1 ) parse_mail( header, section[ 1 ], section_lng[ 1 ] );
+
+ // 日付とID
+ if( i > 2 ) parse_date_id( header, section[ 2 ], section_lng[ 2 ] );
+
+ // 本文
+ const bool digitlink = false;
+ const bool bold = false;
+ if( i > 3 ){
+ // EXTDAT情報を取得
+ if( header->id_header == 1 ) parse_extattr( section[ 3 ], section_lng[ 3 ] );
+
+ header->headinfo->block[ BLOCK_MES ] = create_node_block();
+
+ std::string str_msg;
+ const char* str = section[ 3 ];
+ int lng_msg = section_lng[ 3 ];
+
+ // 文字列置換
+ CORE::ReplaceStr_Manager* mgr = CORE::get_replacestr_manager();
+ if( mgr->list_size( CORE::REPLACETARGET_MESSAGE ) ){
+ str_msg = mgr->replace( str, lng_msg, CORE::REPLACETARGET_MESSAGE );
+ str = str_msg.c_str();
+ lng_msg = str_msg.length();
+ }
+
+ parse_html( str, lng_msg, COLOR_CHAR, digitlink, bold, false );
+ }
+
// 壊れている
if( i != SECTION_NUM ){
@@ -1602,40 +1657,20 @@ const char* NodeTreeBase::add_one_dat_line( const char* datline )
#endif
m_broken = true;
- header->headinfo->block[ BLOCK_NAME ] = create_node_block();
- create_node_text( " 壊れています", COLOR_CHAR );
+ if( i <= 2 ) header->headinfo->block[ BLOCK_MES ] = create_node_block();
+ parse_html( "<br> <br> 壊れています<br>", 32, COLOR_CHAR, digitlink, true, false );
- header->headinfo->block[ BLOCK_MES ] = create_node_block();
const char str_broken[] = "ここ";
- create_node_link( str_broken, strlen( str_broken ) , PROTO_BROKEN, strlen( PROTO_BROKEN ), COLOR_CHAR_LINK, false );
+ create_node_link( str_broken, strlen( str_broken ) , PROTO_BROKEN, strlen( PROTO_BROKEN ), COLOR_CHAR_LINK, COLOR_NONE, false );
create_node_text( "をクリックしてスレを再取得して下さい。", COLOR_CHAR );
-
+
return pos;
}
-
- // 名前
- int color_name = COLOR_CHAR_NAME;
- if( ! section_lng[ 1 ] ) color_name = COLOR_CHAR_NAME_NOMAIL;
- parse_name( header, section[ 0 ], section_lng[ 0 ], color_name );
-
- // メール
- parse_mail( header, section[ 1 ], section_lng[ 1 ] );
-
- // 日付とID
- parse_date_id( header, section[ 2 ], section_lng[ 2 ] );
-
- // 本文
- header->headinfo->block[ BLOCK_MES ] = create_node_block();
-
- const bool digitlink = false;
- const bool bold = false;
- const bool ahref = false;
- parse_html( section[ 3 ], section_lng[ 3 ], COLOR_CHAR, digitlink, bold, ahref );
// サブジェクト
if( header->id_header == 1 ){
- m_subject = std::string( section[ 4 ] ).substr( 0, section_lng[ 4 ] );
+ m_subject.assign( section[ 4 ], section_lng[ 4 ] );
#ifdef _DEBUG
std::cout << "subject = " << m_subject << std::endl;
@@ -1677,11 +1712,23 @@ const char* NodeTreeBase::add_one_dat_line( const char* datline )
//
void NodeTreeBase::parse_name( NODE* header, const char* str, const int lng, const int color_name )
{
- bool digitlink = true;
- const bool bold = true;
const bool ahref = false;
+ std::string str_name;
+ int lng_name = lng;
- const bool defaultname = ( strncmp( m_default_noname.data(), str, lng ) == 0 );
+ // 後ろの空白を除く
+ while( str[ lng_name - 1 ] == ' ' ) --lng_name;
+
+ const bool defaultname = ( m_default_noname.length() == ( size_t )lng_name
+ && m_default_noname.compare( 0, lng_name, str, lng_name ) == 0 );
+
+ // 文字列置換
+ CORE::ReplaceStr_Manager* mgr = CORE::get_replacestr_manager();
+ if( mgr->list_size( CORE::REPLACETARGET_NAME ) ){
+ str_name = mgr->replace( str, lng_name, CORE::REPLACETARGET_NAME );
+ str = str_name.c_str();
+ lng_name = str_name.length();
+ }
header->headinfo->block[ BLOCK_NAMELINK ] = create_node_block();
@@ -1689,43 +1736,46 @@ void NodeTreeBase::parse_name( NODE* header, const char* str, const int lng, con
if( defaultname ) create_node_text( "名前", COLOR_CHAR );
else{
const char namestr[] = "名前";
- create_node_link( namestr, strlen( namestr ) , PROTO_NAME, strlen( PROTO_NAME ), COLOR_CHAR, false );
+ create_node_link( namestr, strlen( namestr ) , PROTO_NAME, strlen( PROTO_NAME ), COLOR_CHAR, COLOR_NONE, false );
}
NODE* node = header->headinfo->block[ BLOCK_NAME ] = create_node_block();
// デフォルト名無しと同じときはアンカーを作らない
if( defaultname ){
- digitlink = false;
- parse_html( str, lng, color_name, digitlink, bold, ahref );
+ constexpr bool digitlink = false;
+ constexpr bool bold = true;
+ parse_html( str, lng_name, color_name, digitlink, bold, ahref );
}
else{
int pos = 0;
int i;
- while( pos < lng ){
+ while( pos < lng_name ){
// トリップなど</b>〜<b>の中の文字列は色を変えて数字をリンクにしない
- for( i = pos; i < lng; ++i ){
+ for( i = pos; i < lng_name; ++i ){
if( str[ i ] == '<'
&& str[ i+1 ] == '/'
&& ( str[ i+2 ] == 'b' || str[ i+2 ] == 'B' )
- && str[ i+3 ] == '>' ) break;
+ && str[ i+3 ] == '>' ){ i += 4; break; }
}
// </b>の前までパース
if( i != pos ){
// デフォルト名無しと同じときはアンカーを作らない
- digitlink = ( strncmp( m_default_noname.data(), str + pos, i - pos ) != 0 );
+ const size_t len = m_default_noname.size();
+ const bool digitlink = m_default_noname.compare( 0, len, str + pos, len );
+ constexpr bool bold = true;
parse_html( str + pos, i - pos, color_name, digitlink, bold, ahref );
}
- if( i >= lng ) break;
- pos = i + 4; // 4 = strlen( "</b>" );
+ if( i >= lng_name ) break;
+ pos = i;
// <b>の位置を探す
- int pos_end = lng;
- for( i = pos; i < lng; ++i ){
+ int pos_end = lng_name;
+ for( i = pos; i < lng_name; ++i ){
if( str[ i ] == '<'
&& ( str[ i+1 ] == 'b' || str[ i+1 ] == 'B' )
&& str[ i+2 ] == '>' ){
@@ -1744,29 +1794,26 @@ void NodeTreeBase::parse_name( NODE* header, const char* str, const int lng, con
#endif
// </b><b>の中をパース
- digitlink = false; // 数字が入ってもリンクしない
+ constexpr bool digitlink = false; // 数字が入ってもリンクしない
+ constexpr bool bold = false;
parse_html( str + pos, pos_end - pos, COLOR_CHAR_NAME_B, digitlink, bold, ahref );
- pos = pos_end + 3; // 3 = strlen( "<b>" );
+ pos = pos_end;
}
}
// plainな名前取得
// 名前あぼーんや名前抽出などで使用する
- if( defaultname ){
- header->headinfo->name = ( char* )m_heap.heap_alloc( lng +2 );
- memcpy( header->headinfo->name, str, lng );
- }
- else{
- std::string str_tmp;
+ std::string str_tmp;
+ node = node->next_node;
+ while( node ){
+ if( node->type == NODE_TEXT && node->text ) str_tmp += node->text;
+ if( node->type == NODE_SP ) str_tmp += " ";
node = node->next_node;
- while( node ){
- if( node->text ) str_tmp += node->text;
- node = node->next_node;
- }
- header->headinfo->name = ( char* )m_heap.heap_alloc( str_tmp.length() +2 );
- memcpy( header->headinfo->name, str_tmp.c_str(), str_tmp.length() );
}
+ header->headinfo->name = ( char* )m_heap.heap_alloc( str_tmp.length() + 1 );
+ memcpy( header->headinfo->name, str_tmp.c_str(), str_tmp.length() );
+ header->headinfo->name[ str_tmp.length() ] = '\0';
}
@@ -1787,16 +1834,26 @@ void NodeTreeBase::parse_mail( NODE* header, const char* str, const int lng )
header->headinfo->block[ BLOCK_MAIL ] = create_node_block();
- if( ! lng ) create_node_text( "[]", color );
+ // 文字列置換
+ std::string str_mail;
+ int lng_mail = lng;
+ CORE::ReplaceStr_Manager* mgr = CORE::get_replacestr_manager();
+ if( mgr->list_size( CORE::REPLACETARGET_MAIL ) ){
+ str_mail = mgr->replace( str, lng, CORE::REPLACETARGET_MAIL );
+ str = str_mail.c_str();
+ lng_mail = str_mail.length();
+ }
+ if( lng_mail == 0 ){
+ create_node_text( "[]", color );
+ }
else{
- create_node_text( "[", color );
-
const bool digitlink = true;
const bool bold = false;
const bool ahref = false;
- parse_html( str, lng, color, digitlink, bold, ahref );
+ create_node_text( "[", color );
+ parse_html( str, lng_mail, color, digitlink, bold, ahref );
create_node_text( "]", color );
}
}
@@ -1807,30 +1864,47 @@ void NodeTreeBase::parse_mail( NODE* header, const char* str, const int lng )
//
void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng )
{
+ std::string str_date;
+ int lng_date = lng;
+
+ // 文字列置換
+ CORE::ReplaceStr_Manager* mgr = CORE::get_replacestr_manager();
+ if( mgr->list_size( CORE::REPLACETARGET_DATE ) ){
+ str_date = mgr->replace( str, lng, CORE::REPLACETARGET_DATE );
+ str = str_date.c_str();
+ lng_date = str_date.length();
+ }
+
+ const bool digitlink = false;
+ const bool bold = false;
+
int start = 0;
int lng_text = 0;
int lng_link_tmp;
char tmplink[ LNG_LINK ];
- int lng_id_tmp;
- char tmpid[ LNG_ID ];
-
header->headinfo->block[ BLOCK_DATE ] = create_node_block();
for(;;){
// 先頭の空白を飛ばす
- while( start + lng_text < lng && str[ start + lng_text ] == ' ' ) ++lng_text;
+ while( start + lng_text < lng_date && str[ start + lng_text ] == ' ' ) ++lng_text;
// 空白ごとにブロック分けしてパースする
int start_block = start + lng_text;
int lng_block = 0; // ブロックの長さ
- while( start_block + lng_block < lng && str[ start_block + lng_block ] != ' ' ) ++lng_block;
+ while( start_block + lng_block < lng_date && str[ start_block + lng_block ] != ' ' ){
+ if( str[ start_block + lng_block ] == '<' )
+ while( start_block + lng_block < lng_date &&
+ str[ start_block + lng_block ] != '>' ) ++lng_block;
+ else
+ ++lng_block;
+ };
+
if( !lng_block ) break;
- if(
- // ID ( ??? の時は除く )
- ( str[ start_block ] == 'I' && str[ start_block + 1 ] == 'D' && str[ start_block + 3 ] != '?' )
+ if( // ID
+ ( str[ start_block ] == 'I' && str[ start_block + 1 ] == 'D' )
// HOST
|| ( str[ start_block + 0 ] == 'H' && str[ start_block + 1 ] == 'O' && str[ start_block + 2 ] == 'S' && str[ start_block + 3 ] == 'T' )
@@ -1845,8 +1919,7 @@ void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng )
// フラッシュ
if( lng_text ){
- if( *( str + start + lng_text - 1 ) == ' ' ) --lng_text;
- create_node_ntext( str + start, lng_text, COLOR_CHAR );
+ parse_html( str + start, lng_text, COLOR_CHAR, digitlink, bold, false );
}
int offset = 0;
@@ -1855,19 +1928,18 @@ void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng )
offset = 5;
// HOST: の場合は途中で空白が入るときがあるので最後までブロックを伸ばす
- lng_block = lng - start_block;
+ lng_block = lng_date - start_block;
}
else if( str[ start_block ] == (char)0xe7 ) offset = 10;
// id 取得
- lng_id_tmp = MIN( lng_block, LNG_ID - 16 );
- memcpy( tmpid, str + start_block, lng_id_tmp );
- tmpid[ lng_id_tmp ] = '\0';
+ int lng_id = MIN( lng_block, (int)( LNG_ID - sizeof( PROTO_ID ) ) );
// リンク文字作成
memcpy( tmplink, PROTO_ID, sizeof( PROTO_ID ) );
- memcpy( tmplink + sizeof( PROTO_ID ) - 1, tmpid, lng_id_tmp + 1 );
- lng_link_tmp = strlen( tmplink );
+ memcpy( tmplink + sizeof( PROTO_ID ) - 1, str + start_block, lng_id );
+ lng_link_tmp = sizeof( PROTO_ID ) - 1 + lng_id;
+ tmplink[ lng_link_tmp ] = '\0';
// 後ろに●が付いていたら取り除く
if( tmplink[ lng_link_tmp - 3 ] == (char)0xe2 && tmplink[ lng_link_tmp - 2 ] == (char)0x97 && tmplink[ lng_link_tmp - 1 ] == (char)0x8f ){
@@ -1877,8 +1949,8 @@ void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng )
// リンク作成
header->headinfo->block[ BLOCK_ID_NAME ] = create_node_block();
- create_node_link( tmpid, offset, tmplink, lng_link_tmp, COLOR_CHAR, false );
- create_node_ntext( tmpid +offset, lng_id_tmp -offset, COLOR_CHAR);
+ create_node_link( str + start_block, offset, tmplink, lng_link_tmp, COLOR_CHAR, COLOR_NONE, false );
+ create_node_ntext( str + start_block + offset, lng_id - offset, COLOR_CHAR );
// 発言回数ノード作成
create_node_idnum();
@@ -1891,26 +1963,33 @@ void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng )
// BE:
else if( str[ start_block ] == 'B' && str[ start_block + 1 ] == 'E' ){
- const int strlen_of_BE = 3; // = strlen( "BE:" );
+ const int strlen_of_BE = strlen( "BE:" );
// フラッシュ
- if( lng_text ) create_node_ntext( str + start, lng_text, COLOR_CHAR );
+ if( lng_text ){
+ parse_html( str + start, lng_text, COLOR_CHAR, digitlink, bold, false );
+ }
// id 取得
int lng_header = 0;
while( str[ start_block + lng_header ] != '-' && lng_header < lng_block ) ++lng_header;
- lng_id_tmp = lng_header - strlen_of_BE;
+ int lng_id = lng_header - strlen_of_BE;
if( str[ start_block + lng_header ] == '-' ) ++lng_header;
- memcpy( tmpid, str + start_block + strlen_of_BE, lng_id_tmp );
- tmpid[ lng_id_tmp ] = '\0';
// リンク文字作成
+ if( ! header->headinfo->block[ BLOCK_ID_NAME ] )
+ header->headinfo->block[ BLOCK_ID_NAME ] = create_node_block();
+ else
+ create_node_space( NODE_SP, COLOR_NONE );
+
memcpy( tmplink, PROTO_BE, sizeof( PROTO_BE ) );
- memcpy( tmplink + sizeof( PROTO_BE ) -1, tmpid, lng_id_tmp + 1 );
+ memcpy( tmplink + sizeof( PROTO_BE ) - 1, str + start_block + strlen_of_BE, lng_id );
+ lng_link_tmp = sizeof( PROTO_BE ) - 1 + lng_id;
+ tmplink[ lng_link_tmp ] = '\0';
// リンク作成
- create_node_link( "?", 1, tmplink, strlen( tmplink ), COLOR_CHAR, false );
- create_node_ntext( str + start_block + lng_header, lng_block - lng_header, COLOR_CHAR);
+ create_node_link( str + start_block + lng_header, lng_block - lng_header,
+ tmplink, lng_link_tmp, COLOR_CHAR, COLOR_NONE, false );
// 次のブロックへ移動
start = start_block + lng_block;
@@ -1923,14 +2002,22 @@ void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng )
&& str[ start_block + 2 ] == ' ' ){
// フラッシュ
- if( lng_text ) create_node_ntext( str + start, lng_text, COLOR_CHAR );
+ if( lng_text ){
+ parse_html( str + start, lng_text, COLOR_CHAR, digitlink, bold, false );
+ }
// </a>までブロックの長さを伸ばす
- while( start_block + lng_block < lng
+ while( start_block + lng_block < lng_date
&& ! ( ( str[ start_block + lng_block -1 ] == 'a' || str[ start_block + lng_block -1 ] == 'A' )
&& str[ start_block + lng_block ] == '>' ) ) ++lng_block;
++lng_block;
+ // リンク作成
+ if( ! header->headinfo->block[ BLOCK_ID_NAME ] )
+ header->headinfo->block[ BLOCK_ID_NAME ] = create_node_block();
+ else
+ create_node_space( NODE_SP, COLOR_NONE );
+
const bool digitlink = false;
const bool bold = false;
const bool ahref = true;
@@ -1942,11 +2029,35 @@ void NodeTreeBase::parse_date_id( NODE* header, const char* str, const int lng )
}
// テキスト(日付含む)
- else lng_text += lng_block;
+ else{
+ bool no_date = true;
+ for( int i = start_block; i < start_block + lng_block; ++i )
+ if( (str[ i ] >= '0' && str[ i ] <= '9') || str[ i ] == ':' ) no_date = false;
+
+ // 日付や時刻を含まないまたは1文字(IDの末尾だけ)はIDノードにする
+ if( ( no_date || lng_block == 1 ) && ! header->headinfo->block[ BLOCK_ID_NAME ] ){
+ if( lng_text ){
+ // フラッシュ
+ parse_html( str + start, lng_text, COLOR_CHAR, digitlink, bold, false );
+ lng_text = 0;
+ }
+
+ // IDノード作成
+ header->headinfo->block[ BLOCK_ID_NAME ] = create_node_block();
+
+ // 次のブロックへ移動
+ start = start_block;
+ }
+
+ lng_text += lng_block;
+ }
}
- // フラッシュ
- if( lng_text ) create_node_ntext( str + start, lng_text, COLOR_CHAR );
+ if( lng_text ){
+ // 末端の空白を削ってフラッシュ
+ while( lng_text > 0 && str[ start + lng_text - 1 ] == ' ' ) --lng_text;
+ parse_html( str + start, lng_text, COLOR_CHAR, digitlink, bold, false );
+ }
}
@@ -1973,6 +2084,13 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
const char* pos = str;
const char* pos_end = str + lng;
int lng_text = 0;
+ int fgcolor = color_text;
+ int fgcolor_bak = color_text;
+ int bgcolor = COLOR_NONE;
+ int bgcolor_bak = COLOR_NONE;
+ bool in_bold = bold;
+ std::vector< std::string >& colors = CORE::get_css_manager()->get_colors();
+ char tmplink[ LNG_LINK ];
if( *pos == ' ' ){
@@ -1981,17 +2099,39 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
// 連続半角空白
if( *pos == ' ' ){
- while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *(pos++);
- create_node_multispace( m_parsed_text, lng_text ); lng_text = 0;
+ while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *pos++;
+ create_node_multispace( m_parsed_text, lng_text, bgcolor ); lng_text = 0;
}
}
- for( ; pos < pos_end; ++pos, digitlink = false ){
+ for( ; pos < pos_end; digitlink = false ){
+
+ ///////////////////////
+ // 半角空白, LF(0x0A), CR(0x0D)
+ if( *pos == ' ' || *pos == 10 || *pos == 13 ){
+
+ // フラッシュしてから半角空白ノードを作る
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
+
+ ++pos;
+ if( pos < pos_end ) create_node_space( NODE_SP, bgcolor );
+
+create_multispace:
+ // 連続スペースノードを作成
+ if( *pos == ' ' ){
+ while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *pos++;
+ if( pos < pos_end ){
+ create_node_multispace( m_parsed_text, lng_text, bgcolor ); lng_text = 0;
+ }
+ }
+
+ continue;
+ }
///////////////////////
// HTMLタグ
- if( *pos == '<' ){
+ else if( *pos == '<' ){
bool br = false;
@@ -2005,7 +2145,7 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
( *( pos + 1 ) == 'a' || *( pos + 1 ) == 'A' ) && *( pos + 2 ) == ' ' ){
// フラッシュ
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
while( pos < pos_end && *pos != '=' ) ++pos;
++pos;
@@ -2032,9 +2172,7 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
const char* pos_str_start = pos;
int lng_str = 0;
- bool exec_decode = false;
- while( pos < pos_end && *pos != '<' ){
- if( *pos == '&' ) exec_decode = true;
+ while( pos < pos_end && ( *pos != '<' || pos[ 1 ] != '/' || ( pos[ 2 ] != 'a' && pos[ 2 ] != 'A' ) || pos[ 3 ] != '>' ) ){
++pos;
++lng_str;
}
@@ -2046,30 +2184,113 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
if( lng_link && lng_str ){
- // 特殊文字デコード
- if( exec_decode ){
-
- for( int pos_tmp = 0; pos_tmp < lng_str; ++ pos_tmp ){
- int n_in = 0;
- int n_out = 0;
- const int ret_decode = DBTREE::decode_char( pos_str_start + pos_tmp, n_in, m_parsed_text + lng_text, n_out, false );
- if( ret_decode != NODE_NONE ){
- lng_text += n_out;
- pos_tmp += n_in;
- pos_tmp--;
- }
- else m_parsed_text[ lng_text++ ] = *( pos_str_start + pos_tmp );
- }
-#ifdef _DEBUG
- m_parsed_text[ lng_text ] = '\0';
- std::cout << m_parsed_text << std::endl;
-#endif
- pos_str_start = m_parsed_text;
- lng_str = lng_text;
- lng_text = 0;
+ // BE link
+ if( memcmp( pos_link_start, "javascript:be(", 14 ) == 0 ){
+ memcpy( tmplink, PROTO_BE, sizeof( PROTO_BE ) );
+ memcpy( tmplink + sizeof( PROTO_BE ) -1, pos_link_start +14, lng_link -14 -2 );
+ create_node_link( pos_str_start, lng_str, tmplink, strlen( tmplink ), fgcolor, bgcolor, in_bold );
}
+ else{
- create_node_link( pos_str_start, lng_str , pos_link_start, lng_link, COLOR_CHAR_LINK, false );
+ if( *pos_link_start == '/' || ! memcmp( pos_link_start, "../", 3 ) ){
+ size_t link_offset = ( *pos_link_start == '/' ) ? 0 : 2;
+
+ // アンカーの判定
+ size_t pos_root = m_url_readcgi.find_first_of( '/', 8 ); // httpsでも8文字目でOK
+ if( pos_root == std::string::npos ||
+ ! m_url_readcgi.compare( pos_root, m_url_readcgi.length() - pos_root, pos_link_start + link_offset, m_url_readcgi.length() - pos_root ) ){
+
+ // アンカーは後で処理するのでここは抜ける
+ pos = pos_str_start;
+ lng_str = 0;
+ }
+ else if( pos_root + lng_link >= LNG_LINK ){
+ // XXX リンクが長すぎる
+ pos = pos_str_start;
+ lng_str = 0;
+ }
+ else{
+ // 相対リンクから完全なURLを作る
+ m_url_readcgi.copy( tmplink, pos_root );
+ memcpy( tmplink + pos_root, pos_link_start + link_offset, lng_link - link_offset );
+ lng_link += pos_root - link_offset;
+ }
+ }
+ else{
+ memcpy( tmplink, pos_link_start, lng_link );
+ tmplink[ lng_link ] = '\0';
+
+ while( remove_imenu( tmplink ) ); // ime.nuなどの除去
+ }
+
+ if( lng_str ){
+
+ for( int pos_tmp = 0; pos_tmp < lng_str; ){
+ const char ch = pos_str_start[ pos_tmp ];
+
+ if( ch == '\t' || ch == '\n' || ch == '\r' || ch == ' ' ){
+ // 空白の連続は削る
+ if( lng_text && m_parsed_text[ lng_text - 1 ] != ' ' ){
+ m_parsed_text[ lng_text++ ] = ' ';
+ }
+ ++pos_tmp;
+ continue;
+ }
+ else if( ch == '<' ){
+ // タグは取り除く
+ while( pos_tmp < lng_str && pos_str_start[ pos_tmp ] != '>' ) ++pos_tmp;
+ if( pos_str_start[ pos_tmp ] == '>' ) ++pos_tmp;
+ continue;
+ }
+ else if( ch != '&' ){
+ // 表示用文字列にコピー
+ m_parsed_text[ lng_text++ ] = pos_str_start[ pos_tmp++ ];
+ continue;
+ }
+
+ // 特殊文字デコード
+ int n_in = 0;
+ int n_out = 0;
+ const int ret_decode = decode_char( pos_str_start + pos_tmp, n_in, m_parsed_text + lng_text, n_out, false );
+ switch( ret_decode ){
+
+ case NODE_HTAB:
+ case NODE_SP:
+ // 空白の連続は無視する
+ if( !lng_text || m_parsed_text[ lng_text - 1 ] != ' ' ){
+ m_parsed_text[ lng_text++ ] = ' ';
+ }
+ pos_tmp += n_in;
+ break;
+
+ case NODE_ZWSP:
+ case NODE_TEXT:
+ if( m_parsed_text[ lng_text ] == '\xc2'
+ && m_parsed_text[ lng_text + 1 ] == '\xa0' ){
+ // &nbsp; は空白に置き換える
+ m_parsed_text[ lng_text++ ] = ' ';
+ }
+ else lng_text += n_out;
+ pos_tmp += n_in;
+ break;
+
+ case NODE_NONE:
+ default:
+ m_parsed_text[ lng_text++ ] = pos_str_start[ pos_tmp++ ];
+ }
+ }
+#ifdef _DEBUG
+ m_parsed_text[ lng_text ] = '\0';
+ std::cout << m_parsed_text << std::endl;
+#endif
+ pos_str_start = m_parsed_text;
+ lng_str = lng_text;
+ lng_text = 0;
+ }
+
+ // アンカーの時はlng_strが0でリンクを作らない
+ if( lng_str ) create_node_link( pos_str_start, lng_str, tmplink, lng_link, COLOR_CHAR_LINK, bgcolor, in_bold );
+ }
}
}
@@ -2104,6 +2325,12 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
&& *( pos + 1 ) == '/'
)
+ // <ul>
+ || (
+ ( *( pos + 1 ) == 'u' || *( pos + 1 ) == 'U' )
+ && ( *( pos + 2 ) == 'l' || *( pos + 2 ) == 'L' )
+ )
+
// </ul>
|| (
( *( pos + 2 ) == 'u' || *( pos + 2 ) == 'U' )
@@ -2130,17 +2357,16 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
) br = true;
- // <li>は・にする
- else if( ( *( pos + 1 ) == 'l' || *( pos + 2 ) == 'L' )
- && ( *( pos + 2 ) == 'i' || *( pos + 3 ) == 'I' )
+ // <li>はBULLET (•)にする
+ else if( ( *( pos + 1 ) == 'l' || *( pos + 1 ) == 'L' )
+ && ( *( pos + 2 ) == 'i' || *( pos + 2 ) == 'I' )
){
pos += 4;
- int n_in = 0;
- int n_out = 0;
- DBTREE::decode_char( "&#12539;", n_in, m_parsed_text + lng_text, n_out, false );
- lng_text += n_out;
+ char const li_str [] = "\xe2\x80\xa2"; // •
+ memcpy( m_parsed_text + lng_text, li_str, sizeof( li_str ) );
+ lng_text += sizeof( li_str ) - 1;
}
// 水平線 <HR>
@@ -2148,7 +2374,7 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
&& ( *( pos + 2 ) == 'r' || *( pos + 2 ) == 'R' ) ){
// フラッシュ
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
// 水平線ノード作成
create_node_hr();
@@ -2156,11 +2382,165 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
pos += 4;
}
- // その他のタグは無視。タグを取り除いて中身だけを見る
+ // ボールド <B>
+ else if( ( *( pos + 1 ) == 'b' || *( pos + 1 ) == 'B' ) && *( pos + 2 ) == '>' ){
+
+ // フラッシュ
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
+ in_bold = true;
+ pos += 3;
+ }
+
+ // </B>
+ else if( *( pos + 1 ) == '/' && ( *( pos + 2 ) == 'b' || *( pos + 2 ) == 'B' )
+ && *( pos + 3 ) == '>' ){
+
+ // フラッシュ
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
+ in_bold = bold;
+ pos += 4;
+ }
+
+ // 閉じるタグの時は文字色を戻す
+ else if( *( pos + 1 ) == '/' ){
+ // フラッシュ
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
+
+ fgcolor = fgcolor_bak;
+ fgcolor_bak = color_text;
+ bgcolor = bgcolor_bak;
+ bgcolor_bak = COLOR_NONE;
+
+ while( pos < pos_end && *pos != '>' ) ++pos;
+ ++pos;
+ }
+
+ // その他のタグはタグを取り除いて中身だけを見る
else {
// フラッシュ
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
+
+ // <span
+ if(( *( pos + 1 ) == 's' || *( pos + 1 ) == 'S' )
+ && ( *( pos + 2 ) == 'p' || *( pos + 2 ) == 'P' )
+ && ( *( pos + 3 ) == 'a' || *( pos + 3 ) == 'A' )
+ && ( *( pos + 4 ) == 'n' || *( pos + 4 ) == 'N' )
+ ){
+ pos += 5;
+
+ // class属性を取り出す
+ std::string classname;
+ if( strncasecmp( pos, " class=\"", 8 ) == 0 ){
+ pos += 8;
+ const char* pos_name = pos;
+ while( *pos != '"' && *pos != '\0' ) ++pos;
+ classname = std::string( pos_name, pos - pos_name );
+ }
+
+ // 文字色を保存
+ fgcolor_bak = fgcolor;
+ bgcolor_bak = bgcolor;
+
+ if( ! classname.empty() && classname != "name" ){
+
+ CORE::Css_Manager* mgr = CORE::get_css_manager();
+ const int classid = mgr->get_classid( classname );
+ if( classid != -1 ){
+ CORE::CSS_PROPERTY css = mgr->get_property( classid );
+ if( css.color != -1 ) fgcolor = css.color;
+ if( css.bg_color != -1 ) bgcolor = css.bg_color;
+ }
+ else{
+ fgcolor = COLOR_CHAR_NAME_B;
+ }
+ }
+ }
+
+ // <mark
+ else if(( *( pos + 1 ) == 'm' || *( pos + 1 ) == 'M' )
+ && ( *( pos + 2 ) == 'a' || *( pos + 2 ) == 'A' )
+ && ( *( pos + 3 ) == 'r' || *( pos + 3 ) == 'R' )
+ && ( *( pos + 4 ) == 'k' || *( pos + 4 ) == 'K' )
+ ){
+
+ CORE::Css_Manager* mgr = CORE::get_css_manager();
+ CORE::CSS_PROPERTY css = mgr->get_property( mgr->get_classid( "mark" ) );
+ fgcolor_bak = fgcolor;
+ bgcolor_bak = bgcolor;
+ if( css.color != -1 ) fgcolor = css.color;
+ if( css.bg_color != -1 ) bgcolor = css.bg_color;
+ }
+
+ if( CONFIG::get_use_color_html() ){
+ // タグで指定された色を使う場合
+
+ while( pos < pos_end && *pos != '>' ){
+ bool background = false;
+
+ while( pos < pos_end && *pos != '>' && *pos != ' '
+ && *pos != '"' && *pos != '\'' ) ++pos;
+
+ if( *pos == '>' ) break;
+
+ else if( ( *pos == ' ' || *pos == '"' || *pos == '\'' )
+ && ! memcmp( pos + 1, "color", 5 ) ) pos += 6;
+
+ else if( ( *pos == ' ' || *pos == '"' || *pos == '\'' )
+ && ! memcmp( pos + 1, "fgcolor", 7 ) ) pos += 8;
+
+ else if( ( *pos == ' ' || *pos == '"' || *pos == '\'' )
+ && ! memcmp( pos + 1, "foreground", 10 ) ) pos += 11;
+
+ else if( ( *pos == ' ' || *pos == '"' || *pos == '\'' )
+ && ! memcmp( pos + 1, "bgcolor", 7 ) ){ pos += 8; background = true; }
+
+ else if( ( *pos == ' ' || *pos == '"' || *pos == '\'' )
+ && ! memcmp( pos + 1, "background-color", 16 ) ){ pos += 17; background = true; }
+
+ else if( ( *pos == ' ' || *pos == '"' || *pos == '\'' )
+ && ! memcmp( pos + 1, "background", 10 ) ){ pos += 11; background = true; }
+
+ else{ ++pos; continue; }
+
+ if( *pos == '=' || *pos == ':' ) ++pos;
+ if( *pos == ' ' || *pos == '"' ) ++pos;
+
+ const char* st = pos;
+ while( pos < pos_end && *pos != '>' && *pos != ' ' && *pos != ';' && *pos != '\'' && *pos != '"' ) ++pos;
+
+ std::string col( st, pos - st );
+ if( col == "transparent" ){
+ // 透明の場合は基本の背景色(でよいか?)
+ if( background ) bgcolor = COLOR_BACK;
+ else fgcolor = COLOR_BACK;
+ continue;
+ }
+
+ const std::string col_str = MISC::htmlcolor_to_str( col ) ;
+ if( col_str.empty() ){
+ MISC::ERRMSG( "unhandled color : " + col );
+ continue;
+ }
+
+ std::vector< std::string >::const_iterator it = colors.begin();
+ for( ; it < colors.end(); ++it )
+ if( ! (*it).compare( col_str ) ) break;
+
+ int num_color;
+ if( it == colors.end() ){
+ colors.push_back( col_str );
+ num_color = colors.size() - 1;
+ }
+ else{
+ num_color = it - colors.begin();
+ }
+
+ // 指定された文字色に変更する
+ if( background ) bgcolor = num_color + USRCOLOR_BASE;
+ else fgcolor = num_color + USRCOLOR_BASE;
+ }
+ }
while( pos < pos_end && *pos != '>' ) ++pos;
++pos;
@@ -2170,8 +2550,7 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
if( br ){
// フラッシュ
- if( *( pos - 1 ) == ' ' ) --lng_text; // 改行前の空白を取り除く
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
// 改行ノード作成
create_node_br();
@@ -2189,13 +2568,11 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
if( *pos == ' ' ){
while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *(pos++);
- create_node_multispace( m_parsed_text, lng_text ); lng_text = 0;
+ create_node_multispace( m_parsed_text, lng_text, bgcolor ); lng_text = 0;
}
}
}
- // forのところで++されるので--しておく
- --pos;
continue;
}
@@ -2205,22 +2582,21 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
int n_in = 0;
int n_out = 0;
char tmpstr[ LNG_LINK +16 ]; // 画面に表示する文字列
- char tmplink[ LNG_LINK +16 ]; // 編集したリンク文字列
- int lng_str = 0, lng_link = strlen( PROTO_ANCHORE );
+ size_t lng_str = 0, lng_link = strlen( PROTO_ANCHORE );
ANCINFO ancinfo[ MAX_ANCINFO ];
- int lng_anc = 0;
+ size_t lng_anc = 0;
int mode = 0;
if( digitlink ) mode = 2;
- if( check_anchor( mode , pos, n_in, tmpstr + lng_str, tmplink + lng_link, LNG_LINK - lng_link, ancinfo + lng_anc ) ){
+ if( check_anchor( mode , pos, n_in, tmpstr, tmplink + lng_link, LNG_LINK - lng_link, ancinfo ) ){
// フラッシュしてからアンカーノードをつくる
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
memcpy( tmplink, PROTO_ANCHORE, strlen( PROTO_ANCHORE ) );
- lng_str += strlen( tmpstr ) - lng_str;
- lng_link += strlen( tmplink ) - lng_link;
+ lng_str = strlen( tmpstr );
+ lng_link = strlen( tmplink );
++lng_anc;
pos += n_in;
@@ -2229,16 +2605,14 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
while( check_anchor( mode, pos, n_in, tmpstr + lng_str, tmplink + lng_link ,
LNG_LINK - lng_link, ancinfo + lng_anc ) ){
- lng_str += strlen( tmpstr ) - lng_str;
- lng_link += strlen( tmplink ) - lng_link;
+ lng_str = strlen( tmpstr );
+ lng_link = strlen( tmplink );
++lng_anc;
pos += n_in;
}
create_node_anc( tmpstr, lng_str, tmplink, lng_link, COLOR_CHAR_LINK, bold, ancinfo, lng_anc );
- // forのところで++されるので--しておく
- --pos;
continue;
}
@@ -2250,79 +2624,62 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
///////////////////////
// リンク(http)のチェック
- char tmpreplace[ LNG_LINK +16 ]; // Urlreplaceで変換した後のリンク文字列
- int lng_replace = 0;
- int linktype = check_link( pos, (int)( pos_end - pos ), n_in, tmplink, LNG_LINK );
+ n_in = pos_end - pos;
+ lng_str = lng_link = LNG_LINK;
+ int linktype = check_link( pos, n_in, (char*)tmpstr, lng_str, (char*)tmplink, lng_link );
+
if( linktype != MISC::SCHEME_NONE ){
// リンクノードで実際にアクセスするURLの変換
while( remove_imenu( tmplink ) ); // ime.nuなどの除去
- lng_link = convert_amp( tmplink, strlen( tmplink ) ); // &amp; → &
+ lng_link = strlen( tmplink );
// Urlreplaceによる正規表現変換
- std::string tmpurl( tmplink, lng_link );
- if( CORE::get_urlreplace_manager()->exec( tmpurl ) == false ){
- // 変換されてない
- lng_replace = lng_link;
- memcpy( tmpreplace, tmplink, lng_replace +1 );
-
- } else {
- if( tmpurl.size() > LNG_LINK ){
- MISC::ERRMSG( std::string( "too long replaced url : " ) + tmplink );
+ std::string tmpreplace( tmplink, lng_link );
+ if( CORE::get_urlreplace_manager()->exec( tmpreplace ) ){
+ int delim_pos = 0;
+ if( tmpreplace.length() >= LNG_LINK ){
// 変換後のURLが長すぎるので、元のURLのままにする
- lng_replace = lng_link;
- memcpy( tmpreplace, tmplink, lng_replace +1 );
- } else {
- // 正常に変換された
- lng_replace = tmpurl.size();
- memcpy( tmpreplace, tmpurl.c_str(), lng_replace +1 );
+ MISC::ERRMSG( std::string( "too long replaced url : " ) + tmplink );
+ tmpreplace.assign( tmplink, lng_link );
- // 正規表現変換の結果、スキームだけの簡易チェックをする
- int delim_pos = 0;
- if( MISC::SCHEME_NONE == MISC::is_url_scheme( tmpreplace, &delim_pos ) ){
- // スキーム http:// が消えていた
- linktype = MISC::SCHEME_NONE;
- }
+ // 正常に変換された結果、スキームだけの簡易チェックをする
+ } else if( MISC::SCHEME_NONE == MISC::is_url_scheme( tmpreplace.c_str(), &delim_pos ) ){
+ // プロトコルスキームが消えていた
+ memcpy( m_parsed_text + lng_text, tmpstr, lng_str );
+ lng_text += lng_str;
+ pos += n_in;
+ continue;
}
}
- }
- // リンクノードか再チェック
- if( linktype != MISC::SCHEME_NONE ){
- // フラッシュしてからリンクノードつくる
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
- // リンクノードの表示テキスト
- memcpy( tmpstr, pos, n_in );
- tmpstr[ n_in ] = '\0';
- lng_str = convert_amp( tmpstr, n_in ); // &amp; → &
+ // フラッシュしてからリンクノードつくる
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
// ssspアイコン
if( linktype == MISC::SCHEME_SSSP ){
- create_node_sssp( tmpreplace, lng_replace );
+ create_node_sssp( tmpreplace.c_str(), tmpreplace.length() );
}
else {
// Urlreplaceによる画像コントロールを取得する
- int imgctrl = CORE::get_urlreplace_manager()->get_imgctrl( std::string( tmpreplace, lng_replace ) );
+ int imgctrl = CORE::get_urlreplace_manager()->get_imgctrl( tmpreplace );
// youtubeなどのサムネイル画像リンク
if( imgctrl & CORE::IMGCTRL_THUMBNAIL ){
- create_node_thumbnail( tmpstr, lng_str, tmplink , lng_link, tmpreplace, lng_replace, COLOR_CHAR_LINK, bold );
+ create_node_thumbnail( tmpstr, lng_str, tmplink , lng_link, tmpreplace.c_str(), tmpreplace.length(), COLOR_CHAR_LINK, bold );
}
// 画像リンク
- else if( DBIMG::get_type_ext( tmpreplace, lng_replace ) != DBIMG::T_UNKNOWN ){
- create_node_img( tmpstr, lng_str, tmpreplace , lng_replace, COLOR_IMG_NOCACHE, bold );
+ else if( DBIMG::get_type_ext( tmpreplace.c_str(), tmpreplace.length() ) != DBIMG::T_UNKNOWN ){
+ create_node_img( tmpstr, lng_str, tmpreplace.c_str(), tmpreplace.length(), COLOR_IMG_NOCACHE, bold );
}
// 一般リンク
- else create_node_link( tmpstr, lng_str, tmpreplace , lng_replace, COLOR_CHAR_LINK, bold );
+ else create_node_link( tmpstr, lng_str, tmpreplace.c_str(), tmpreplace.length(), COLOR_CHAR_LINK, bgcolor, bold );
}
pos += n_in;
-
- // forのところで++されるので--しておく
- --pos;
continue;
}
@@ -2330,65 +2687,88 @@ void NodeTreeBase::parse_html( const char* str, const int lng, const int color_t
// 特殊文字デコード
if( *pos == '&' ){
- const int ret_decode = DBTREE::decode_char( pos, n_in, m_parsed_text + lng_text, n_out, false );
+ const int ret_decode = decode_char( pos, n_in, m_parsed_text + lng_text, n_out, false );
if( ret_decode != NODE_NONE ){
// 文字以外の空白ノードならフラッシュして空白ノード追加
if( ret_decode != NODE_TEXT ){
- create_node_ntext( m_parsed_text, lng_text, color_text, bold );
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold );
lng_text = 0;
- create_node_space( ret_decode );
+ create_node_space( ret_decode, bgcolor );
+ }
+ else if( m_parsed_text[ lng_text ] == '\xc2'
+ && m_parsed_text[ lng_text + 1 ] == '\xa0' ){
+ // &nbsp; は空白に置き換える
+ m_parsed_text[ lng_text++ ] = ' ';
}
else lng_text += n_out;
pos += n_in;
-
- // forのところで++されるので--しておく
- --pos;
continue;
}
}
///////////////////////
// 水平タブ(0x09)
- if( *pos == 0x09 ){
+ else if( *pos == '\t' ){
// フラッシュしてからタブノードをつくる
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
- create_node_htab();
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
+ create_node_space( NODE_HTAB, bgcolor );
+ ++pos;
+
+ goto create_multispace;
+ }
+
+ ///////////////////////
+ // フォームフィード(0x0C)
+ else if( *pos == '\f' ){
+
+ // フラッシュしてからZWSPノードをつくる
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold ); lng_text = 0;
+ create_node_space( NODE_ZWSP, bgcolor );
+ ++pos;
+
continue;
}
///////////////////////
- // LF(0x0A), CR(0x0D)
- if( *pos == 0x0A || *pos == 0x0D ){
+ // NBSP(0xC2 0xA0)
+ else if( *pos == '\xc2' && *(pos + 1) == '\xa0' ){
+ // 空白に置き換える
+ m_parsed_text[ lng_text++ ] = ' ';
+ pos += 2;
- // 無視する
continue;
}
///////////////////////
- // 連続半角空白
- if( *pos == ' ' && *( pos + 1 ) == ' ' ){
+ // その他のASCIIおよびマルチバイト文字
+ switch( MISC::utf8bytes( pos ) ){
+ case 4: m_parsed_text[ lng_text++ ] = *pos++;
+ // fallthrough
+ case 3: m_parsed_text[ lng_text++ ] = *pos++;
+ // fallthrough
+ case 2: m_parsed_text[ lng_text++ ] = *pos++;
+ // fallthrough
+ case 1: m_parsed_text[ lng_text++ ] = *pos++;
+ break;
+ default:
+ // Iconvでエンコード変換済みなので不正な文字が
+ // ここで検出されるのは何かがおかしい
+ MISC::ERRMSG( "invalid char = " + MISC::itostr( (unsigned char) *pos ) );
- m_parsed_text[ lng_text++ ] = *(pos++);
-
- // フラッシュしてから連続半角ノードを作る
- create_node_ntext( m_parsed_text, lng_text, color_text, bold ); lng_text = 0;
-
- while( *pos == ' ' ) m_parsed_text[ lng_text++ ] = *(pos++);
- create_node_multispace( m_parsed_text, lng_text ); lng_text = 0;
-
- // forのところで++されるので--しておく
- --pos;
- continue;
+ // REPLACEMENT CHARACTERに置き換える
+ ++pos;
+ m_parsed_text[ lng_text++ ] = static_cast< char >( 0xef );
+ m_parsed_text[ lng_text++ ] = static_cast< char >( 0xbf );
+ m_parsed_text[ lng_text++ ] = static_cast< char >( 0xbd );
+ break;
}
-
- m_parsed_text[ lng_text++ ] = *pos;
}
- create_node_ntext( m_parsed_text, lng_text, color_text, bold );
+ create_node_ntext( m_parsed_text, lng_text, fgcolor, bgcolor, in_bold );
}
@@ -2498,7 +2878,7 @@ void NodeTreeBase::parse_write( const char* str, const int lng, const int max_ln
else if( *pos == '&' && *( pos + 1 ) == '#' && ( lng_num = MISC::spchar_number_ln( pos, offset_num ) ) != -1 ){
const int num = MISC::decode_spchar_number( pos, offset_num, lng_num );
- const int n_out = MISC::ucs2toutf8( num, pos_write );
+ const int n_out = MISC::cptoutf8( num, pos_write );
pos_write += n_out;
pos += offset_num + lng_num;
@@ -2680,124 +3060,136 @@ bool NodeTreeBase::check_anchor( const int mode, const char* str_in,
//
// 入力
// str_in : 入力文字列の先頭アドレス
-// lng_str : str_inのバッファサイズ
+// lng_in : str_inのバッファサイズ
+// lng_text : str_textのバッファサイズ
// lng_link : str_linkのバッファサイズ
-// linktype : is_url_scheme()のリタンコード
-// delim_pos : is_url_scheme()で得たスキーム文字列の長さ
//
// 出力
-// n_in : str_in から何バイト読み取ったか
+// lng_in : str_in から何バイト読み取ったか
+// str_text : リンクの表示文字列
+// lng_text : str_textのサイズ
// str_link : リンクの文字列
+// lng_link : str_linkのサイズ
//
// 戻り値 : リンクのタイプ(例えばSCHEME_HTTPなど)
//
// 注意 : MISC::is_url_scheme() と MISC::is_url_char() の仕様に合わせる事
//
-int NodeTreeBase::check_link_impl( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link, const int linktype, const int delim_pos )
+int NodeTreeBase::check_link( const char* str_in, int& lng_in, char* str_text, size_t& lng_text, char* str_link, size_t& lng_link )
{
+ int delim_pos = 0;
+ int linktype = MISC::is_url_scheme( str_in, &delim_pos );
+ if( linktype == MISC::SCHEME_NONE ) return linktype;
+
// CONFIG::get_loose_url() == true の時はRFCで規定されていない文字も含める
const bool loose_url = CONFIG::get_loose_url();
- // リンクの長さを取得
- n_in = delim_pos;
- int n_in_tmp, n_out_tmp;
- char buf[16];
-
- while( n_in < lng_in ){
-
- // URLとして扱う文字かどうか
- if ( MISC::is_url_char( str_in + n_in, loose_url ) == false ) break;
-
- // HTML特殊文字( &〜; )
- if ( *( str_in + n_in ) == '&' &&
- DBTREE::decode_char( str_in + n_in, n_in_tmp, buf, n_out_tmp, false ) != DBTREE::NODE_NONE ){
-
- // デコード結果が"&(&amp;)"でないもの
- if( n_out_tmp != 1 || buf[0] != '&' ) break;
- }
-
- n_in++;
- }
-
- // URLとして短かすぎる場合は除外する( 最短ドメイン名の例 "1.cc" )
- if( n_in - delim_pos < 4 ) return MISC::SCHEME_NONE;
-
- // URL出力バッファより長いときも除外する( 一般に256バイトを超えるとキャッシュをファイル名として扱えなくなる )
- if( lng_link <= n_in ) return MISC::SCHEME_NONE;
-
- char *pos = str_link;
+ const char *pos_in = str_in;
+ char *pos_text = str_text;
+ char *pos_link = str_link;
+ const char* pos_in_end = str_in + lng_in;
+ const char* pos_text_end = str_text + lng_text;
+ const char* pos_link_end = str_link + lng_link;
// URLスキームを修正
- int str_pos = 0;
switch( linktype ){
-
- // ttp -> http
- case MISC::SCHEME_TTP:
-
- if( n_in + 1 >= lng_link ) return MISC::SCHEME_NONE;
-
- *pos = 'h';
- pos++;
- break;
-
- // tp -> http
- case MISC::SCHEME_TP:
-
- if( n_in + 2 >= lng_link ) return MISC::SCHEME_NONE;
-
- *pos = 'h';
- *(++pos) = 't';
- pos++;
- break;
-
- // sssp -> http
case MISC::SCHEME_SSSP:
-
- *pos = 'h';
- *(++pos) = 't';
- *(++pos) = 't';
- pos++;
- str_pos = 3;
- break;
+ case MISC::SCHEME_HTTP: *pos_text++ = *pos_in++;
+ // fallthrough
+ case MISC::SCHEME_TTP: *pos_text++ = *pos_in++;
+ // fallthrough
+ case MISC::SCHEME_TP: *pos_text++ = *pos_in++;
}
- // srr_inの文字列をstr_linkにコピー
- int i = str_pos;
- for( ; i < n_in; i++, pos++ ){
+ // str_inの文字列をdelim_posまでコピー
+ *pos_link++ = 'h'; *pos_link++ = 't'; *pos_link++ = 't';
+ for( ; pos_in < str_in + delim_pos; ++pos_in ) *pos_text++ = *pos_link++ = *pos_in;
- *pos = str_in[ i ];
+ // str_inの残り文字列をstr_linkにコピー
+ while( pos_in < pos_in_end ){
+ int n_in_tmp, n_out_tmp;
+ char ch = *pos_in;
+
+ // 文字参照を変換
+ if( ch == '&' && decode_char( pos_in, n_in_tmp, pos_link, n_out_tmp, false ) != NODE_NONE ){
+ // URLとして扱う文字かどうか
+ if( n_out_tmp == 1 && MISC::is_url_char( pos_link, loose_url ) ){
+ ch = *pos_text++ = *pos_link++;
+ pos_in += n_in_tmp;
+ }
+ else{
+ break;
+ }
+ }
+
+ // URLとして扱う文字かどうか
+ else if( MISC::is_url_char( pos_in, loose_url ) ){
+ *pos_text++ = *pos_link++ = ch;
+ ++pos_in;
+ }
+ else{
+ break;
+ }
+
+ if( pos_text >= pos_text_end || pos_link >= pos_link_end ) return MISC::SCHEME_NONE;
// loose_urlで含める"^"と"|"をエンコードする
// "[]"はダウンローダに渡す用途のためにエンコードしないでおく
- if( loose_url == true ){
+ if( loose_url ){
- if( str_in[ i ] == '^' ){
+ if( ch == '^' ){ // '^' → "%5E"(+2Byte)
+ if( pos_link + 2 >= pos_link_end ) return MISC::SCHEME_NONE;
- // '^' → "%5E"(+2Byte)
- if( n_in + 2 >= lng_link ) return MISC::SCHEME_NONE;
-
- *pos = '%';
- *(++pos) = '5';
- *(++pos) = 'E';
+ *( pos_link - 1 ) = '%';
+ *pos_link++ = '5';
+ *pos_link++ = 'E';
}
- else if( str_in[ i ] == '|' ){
+ else if( ch == '|' ){ // '|' → "%7C"(+2Byte)
+ if( pos_link + 2 >= pos_link_end ) return MISC::SCHEME_NONE;
- // '|' → "%7C"(+2Byte)
- if( n_in + 2 >= lng_link ) return MISC::SCHEME_NONE;
-
- *pos = '%';
- *(++pos) = '7';
- *(++pos) = 'C';
+ *( pos_link - 1 ) = '%';
+ *pos_link++ = '7';
+ *pos_link++ = 'C';
}
}
}
// str_linkの終端
- *pos = '\0';
+ *pos_text = *pos_link = '\0';
+ lng_in = pos_in - str_in;
+ lng_text = pos_text - str_text;
+ lng_link = pos_link - str_link;
+
+ // パーセントコードの処理
+ if( CONFIG::get_percent_decode() && memchr( str_text, '%', lng_text ) != NULL )
+ {
+ std::string tmp = MISC::url_decode( str_text, lng_text );
+
+ const CharCode charcode = MISC::judge_char_code( tmp );
+
+ if( charcode == CHARCODE_SJIS || charcode == CHARCODE_EUCJP ||
+ charcode == CHARCODE_JIS ){
+ tmp = MISC::Iconv( tmp, charcode, CHARCODE_UTF8 );
+ }
+
+ if( charcode != CHARCODE_UNKNOWN ){
+ // 改行はパーセントエンコード( 元に戻す )
+ tmp = MISC::replace_newlines_to_str( tmp, "%0A" );
+
+ if( tmp.length() < lng_text ){
+ tmp.copy( str_text, std::string::npos );
+ lng_text = tmp.length();
+ }
+ }
+ }
+
+ // URLとして短かすぎる場合は除外する( 最短ドメイン名の例 "1.cc" )
+ if( lng_in - delim_pos < 4 ) return MISC::SCHEME_NONE;
+
#ifdef _DEBUG
std::cout << str_link << std::endl
- << "len = " << strlen( str_link ) << " lng_link = " << lng_link << " n_in = " << n_in << std::endl;
+ << " lng_link = " << lng_link << " lng_in = " << lng_in << std::endl;
#endif
return linktype;
@@ -2835,6 +3227,7 @@ void NodeTreeBase::copy_abone_info( const std::list< std::string >& list_abone_i
const std::list< std::string >& list_abone_regex,
const std::unordered_set< int >& abone_reses,
const bool abone_transparent, const bool abone_chain, const bool abone_age,
+ const bool abone_default_name, const bool abone_noid,
const bool abone_board, const bool abone_global )
{
m_list_abone_id = list_abone_id;
@@ -2843,17 +3236,40 @@ void NodeTreeBase::copy_abone_info( const std::list< std::string >& list_abone_i
m_list_abone_id_board = DBTREE::get_abone_list_id_board( m_url );
m_list_abone_name_board = DBTREE::get_abone_list_name_board( m_url );
+ std::list< std::string > list_str;
+ const bool icase = CONFIG::get_abone_icase();
+ const bool newline = true;
+ const bool wchar = CONFIG::get_abone_wchar();
+
// 設定ファイルには改行は"\\n"で保存されているので "\n" に変換する
m_list_abone_word = MISC::replace_str_list( list_abone_word, "\\n", "\n" );
- m_list_abone_regex = MISC::replace_str_list( list_abone_regex, "\\n", "\n" );
+ list_str = MISC::replace_str_list( list_abone_regex, "\\n", "\n" );
+ m_list_abone_regex.clear();
+ for( std::list< std::string >::const_iterator it = list_str.begin();
+ it != list_str.end(); it++ ){
+ m_list_abone_regex.push_back( JDLIB::RegexPattern() );
+ m_list_abone_regex.rbegin()->set( *it, icase, newline, false, wchar );
+ }
m_list_abone_word_board = DBTREE::get_abone_list_word_board( m_url );
m_list_abone_word_board = MISC::replace_str_list( m_list_abone_word_board, "\\n", "\n" );
- m_list_abone_regex_board = DBTREE::get_abone_list_regex_board( m_url );
- m_list_abone_regex_board = MISC::replace_str_list( m_list_abone_regex_board, "\\n", "\n" );
+ list_str = DBTREE::get_abone_list_regex_board( m_url );
+ list_str = MISC::replace_str_list( list_str, "\\n", "\n" );
+ m_list_abone_regex_board.clear();
+ for( std::list< std::string >::const_iterator it = list_str.begin();
+ it != list_str.end(); it++ ){
+ m_list_abone_regex_board.push_back( JDLIB::RegexPattern() );
+ m_list_abone_regex_board.rbegin()->set( *it, icase, newline, false, wchar );
+ }
m_list_abone_word_global = MISC::replace_str_list( CONFIG::get_list_abone_word(), "\\n", "\n" );
- m_list_abone_regex_global = MISC::replace_str_list( CONFIG::get_list_abone_regex(), "\\n", "\n" );
+ list_str = MISC::replace_str_list( CONFIG::get_list_abone_regex(), "\\n", "\n" );
+ m_list_abone_regex_global.clear();
+ for( std::list< std::string >::const_iterator it = list_str.begin();
+ it != list_str.end(); it++ ){
+ m_list_abone_regex_global.push_back( JDLIB::RegexPattern() );
+ m_list_abone_regex_global.rbegin()->set( *it, icase, newline, false, wchar );
+ }
m_abone_reses = abone_reses;
@@ -2864,6 +3280,8 @@ void NodeTreeBase::copy_abone_info( const std::list< std::string >& list_abone_i
else m_abone_chain = abone_chain;
m_abone_age = abone_age;
+ m_abone_default_name = abone_default_name;
+ m_abone_noid = abone_noid;
m_abone_board = abone_board;
m_abone_global = abone_global;
}
@@ -2881,8 +3299,8 @@ void NodeTreeBase::update_abone_all()
update_abone( 1, m_id_header );
// 発言数更新
- clear_id_name();
- update_id_name( 1, m_id_header );
+ //clear_id_name();
+ //update_id_name( 1, m_id_header );
// 参照状態更新
clear_reference();
@@ -2941,23 +3359,32 @@ bool NodeTreeBase::check_abone_id( const int number )
const bool check_id = ! m_list_abone_id.empty();
const bool check_id_board = ! m_list_abone_id_board.empty();
- if( !check_id && !check_id_board ) return false;
+ if( !m_abone_noid && !check_id && !check_id_board ) return false;
NODE* head = res_header( number );
if( ! head ) return false;
if( ! head->headinfo ) return false;
if( head->headinfo->abone ) return true;
- if( ! head->headinfo->block[ BLOCK_ID_NAME ] ) return false;
+ if( ! head->headinfo->block[ BLOCK_ID_NAME ] ){
+ // ID無し
+ if( m_abone_noid ){
+ head->headinfo->abone = true;
+ return true;
+ }
+ else return false;
+ }
- const int ln_protoid = strlen( PROTO_ID );
+ NODE* idnode = head->headinfo->block[ BLOCK_ID_NAME ]->next_node;
+ if( ! idnode || ! idnode->linkinfo ) return false;
+
+ const char* protoid = idnode->linkinfo->link + strlen( PROTO_ID );
// ローカルID
if( check_id ){
std::list< std::string >::iterator it = m_list_abone_id.begin();
for( ; it != m_list_abone_id.end(); ++it ){
- // std::string の find は遅いのでstrcmp使う
- if( strcmp( head->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link + ln_protoid, ( *it ).c_str() ) == 0 ){
+ if( *protoid == ( *it )[ 0 ] && ( *it ).compare( protoid ) == 0 ){
head->headinfo->abone = true;
return true;
}
@@ -2969,8 +3396,7 @@ bool NodeTreeBase::check_abone_id( const int number )
std::list< std::string >::iterator it = m_list_abone_id_board.begin();
for( ; it != m_list_abone_id_board.end(); ++it ){
- // std::string の find は遅いのでstrcmp使う
- if( strcmp( head->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link + ln_protoid, ( *it ).c_str() ) == 0 ){
+ if( *protoid == ( *it )[ 0 ] && ( *it ).compare( protoid ) == 0 ){
head->headinfo->abone = true;
return true;
}
@@ -2992,7 +3418,7 @@ bool NodeTreeBase::check_abone_name( const int number )
const bool check_name_board = ! m_list_abone_name_board.empty();
const bool check_name_global = ! CONFIG::get_list_abone_name().empty();
- if( !check_name && !check_name_board && !check_name_global ) return false;
+ if( !m_abone_default_name && !check_name && !check_name_board && !check_name_global ) return false;
NODE* head = res_header( number );
if( ! head ) return false;
@@ -3000,6 +3426,15 @@ bool NodeTreeBase::check_abone_name( const int number )
if( head->headinfo->abone ) return true;
if( ! head->headinfo->name ) return false;
+ // デフォルト名無し
+ if( m_abone_default_name && head->headinfo->block[ BLOCK_NAMELINK ] ){
+ NODE* idnode = head->headinfo->block[ BLOCK_NAMELINK ]->next_node;
+ if( idnode && ! idnode->linkinfo ){
+ head->headinfo->abone = true;
+ return true;
+ }
+ }
+
std::list< std::string >::const_iterator it;
const std::string name_str( head->headinfo->name );
@@ -3091,15 +3526,11 @@ bool NodeTreeBase::check_abone_word( const int number )
const std::string res_str = get_res_str( number );
JDLIB::Regex regex;
const size_t offset = 0;
- const bool icase = CONFIG::get_abone_icase();
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = CONFIG::get_abone_wchar();
// ローカル NG word
if( check_word ){
- std::list< std::string >::iterator it = m_list_abone_word.begin();
+ std::list< std::string >::const_iterator it = m_list_abone_word.begin();
for( ; it != m_list_abone_word.end(); ++it ){
if( res_str.find( *it ) != std::string::npos ){
head->headinfo->abone = true;
@@ -3111,9 +3542,8 @@ bool NodeTreeBase::check_abone_word( const int number )
// ローカル NG regex
if( check_regex ){
- std::list< std::string >::iterator it = m_list_abone_regex.begin();
- for( ; it != m_list_abone_regex.end(); ++it ){
- if( regex.exec( *it, res_str, offset, icase, newline, usemigemo, wchar ) ){
+ for( const JDLIB::RegexPattern& pattern : m_list_abone_regex ) {
+ if( regex.match( pattern, res_str, offset ) ){
head->headinfo->abone = true;
return true;
}
@@ -3123,7 +3553,7 @@ bool NodeTreeBase::check_abone_word( const int number )
// 板レベル NG word
if( check_word_board ){
- std::list< std::string >::iterator it = m_list_abone_word_board.begin();
+ std::list< std::string >::const_iterator it = m_list_abone_word_board.begin();
for( ; it != m_list_abone_word_board.end(); ++it ){
if( res_str.find( *it ) != std::string::npos ){
head->headinfo->abone = true;
@@ -3135,9 +3565,8 @@ bool NodeTreeBase::check_abone_word( const int number )
// 板レベル NG regex
if( check_regex_board ){
- std::list< std::string >::iterator it = m_list_abone_regex_board.begin();
- for( ; it != m_list_abone_regex_board.end(); ++it ){
- if( regex.exec( *it, res_str, offset, icase, newline, usemigemo, wchar ) ){
+ for( const JDLIB::RegexPattern& pattern : m_list_abone_regex_board ) {
+ if( regex.match( pattern, res_str, offset ) ){
head->headinfo->abone = true;
return true;
}
@@ -3147,7 +3576,7 @@ bool NodeTreeBase::check_abone_word( const int number )
// 全体 NG word
if( check_word_global ){
- std::list< std::string >::iterator it = m_list_abone_word_global.begin();
+ std::list< std::string >::const_iterator it = m_list_abone_word_global.begin();
for( ; it != m_list_abone_word_global.end(); ++it ){
if( res_str.find( *it ) != std::string::npos ){
head->headinfo->abone = true;
@@ -3159,9 +3588,8 @@ bool NodeTreeBase::check_abone_word( const int number )
// 全体 NG regex
if( check_regex_global ){
- std::list< std::string >::iterator it = m_list_abone_regex_global.begin();
- for( ; it != m_list_abone_regex_global.end(); ++it ){
- if( regex.exec( *it, res_str, offset, icase, newline, usemigemo, wchar ) ){
+ for( const JDLIB::RegexPattern& pattern : m_list_abone_regex_global ) {
+ if( regex.match( pattern, res_str, offset ) ){
head->headinfo->abone = true;
return true;
}
@@ -3448,28 +3876,74 @@ void NodeTreeBase::clear_id_name()
void NodeTreeBase::update_id_name( const int from_number, const int to_number )
{
if( ! CONFIG::get_check_id() ) return;
+
if( empty() ) return;
if( to_number < from_number ) return;
+ for( int i = from_number ; i <= to_number; ++i ) check_id_name( i );
+}
- //まずIDをキーにしたレス番号の一覧を集計
- for( int i = from_number ; i <= to_number; ++i ) {
- NODE* header = res_header( i );
- if( ! header ) continue;
- if( ! header->headinfo->block[ BLOCK_ID_NAME ] ) continue;
- std::string str_id = header->headinfo->block[ BLOCK_ID_NAME ]->next_node->linkinfo->link;
- m_map_id_name_resnumber[ str_id ].insert( i );
+
+//
+// number番のレスの発言数を更新
+//
+void NodeTreeBase::check_id_name( const int number )
+{
+ NODE* header = res_header( number );
+ if( ! header ) return;
+// if( header->headinfo->abone ) return;
+ if( ! header->headinfo->block[ BLOCK_ID_NAME ] ) return;
+
+ NODE* idnode = header->headinfo->block[ BLOCK_ID_NAME ]->next_node;
+ if( ! idnode || ! idnode->linkinfo ) return;
+
+ const char* str_id = idnode->linkinfo->link;
+
+ // ID:???はカウントしない
+ if( str_id[ sizeof( PROTO_ID ) + 2 ] == '?' ) return;
+
+ // 同じIDのレスを持つ一つ前のレスを探す
+ if( ! m_idhash ){
+ m_idhash = ( IDHASH** ) m_heap.heap_alloc( sizeof( IDHASH* ) * IDHASH_TBLSIZE );
}
-
- //集計したものを元に各ノードの情報を更新
- for( const auto &a: m_map_id_name_resnumber ){ // ID = a.first, レス番号の一覧 = a.second
- for( const auto &num: a.second ) {
- NODE* header = res_header( num );
- if( ! header ) continue;
- if( ! header->headinfo->block[ BLOCK_ID_NAME ] ) continue;
- set_num_id_name( header, a.second.size() );
+ size_t key = MISC::fnv_hash( str_id, strlen( str_id ) ) % IDHASH_TBLSIZE;
+ IDHASH* idhash = m_idhash[ key ];
+ if( ! idhash ){
+ idhash = ( IDHASH* )m_heap.heap_alloc( sizeof( IDHASH ) );
+ m_idhash[ key ] = idhash;
+ idhash->id = str_id;
+ }
+ else do{
+ const int cmp = strcmp( str_id, idhash->id );
+ if( cmp == 0 ) break;
+ if( ! idhash->child[ cmp>0 ] ){
+ idhash->child[ cmp>0 ] = ( IDHASH* )m_heap.heap_alloc( sizeof( IDHASH ) );
+ idhash = idhash->child[ cmp>0 ];
+ idhash->id = str_id;
+ break;
}
- }
+ idhash = idhash->child[ cmp>0 ];
+ } while( true );
+
+ NODE* prehead = res_header( idhash->num );
+ idhash->num = number;
+
+ // 見つからなかった
+ if( ! prehead ) set_num_id_name( header, 1, NULL );
+
+ // 見つかった
+ else{
+
+ set_num_id_name( header, prehead->headinfo->num_id_name+1, prehead );
+
+ // 以前に出た同じIDのレスの発言数を更新
+ NODE* tmphead = prehead;
+ while( tmphead ){
+
+ set_num_id_name( tmphead, tmphead->headinfo->num_id_name+1, tmphead->headinfo->pre_id_name_header );
+ tmphead = tmphead->headinfo->pre_id_name_header;
+ }
+ }
}
@@ -3478,15 +3952,18 @@ void NodeTreeBase::update_id_name( const int from_number, const int to_number )
//
// IDノードの色も変更する
//
-void NodeTreeBase::set_num_id_name( NODE* header, const int num_id_name )
+void NodeTreeBase::set_num_id_name( NODE* header, const int num_id_name, NODE* pre_id_name_header )
{
- if( ! header->headinfo->block[ BLOCK_ID_NAME ] ) return;
+ if( ! header->headinfo->block[ BLOCK_ID_NAME ] ||
+ ! header->headinfo->block[ BLOCK_ID_NAME ]->next_node ) return;
header->headinfo->num_id_name = num_id_name;
+ header->headinfo->pre_id_name_header = pre_id_name_header;
- if( num_id_name >= m_num_id[ LINK_HIGH ] ) header->headinfo->block[ BLOCK_ID_NAME ]->next_node->color_text = COLOR_CHAR_LINK_ID_HIGH;
- else if( num_id_name >= m_num_id[ LINK_LOW ] ) header->headinfo->block[ BLOCK_ID_NAME ]->next_node->color_text = COLOR_CHAR_LINK_ID_LOW;
- else header->headinfo->block[ BLOCK_ID_NAME ]->next_node->color_text = COLOR_CHAR;
+ NODE* idnode = header->headinfo->block[ BLOCK_ID_NAME ]->next_node;
+ if( num_id_name >= m_num_id[ LINK_HIGH ] ) idnode->color_text = COLOR_CHAR_LINK_ID_HIGH;
+ else if( num_id_name >= m_num_id[ LINK_LOW ] ) idnode->color_text = COLOR_CHAR_LINK_ID_LOW;
+ else idnode->color_text = COLOR_CHAR;
}
@@ -3514,7 +3991,7 @@ void NodeTreeBase::check_fontid( const int number )
// ヘッダノードには、フォント判定済みの意味を兼ねて、デフォルトフォントを設定しておく
head->fontid = FONT_DEFAULT;
- if( m_aa_regex.empty() ) return;
+ if( ! m_aa_regex.compiled() ) return;
char fontid_mes = FONT_DEFAULT; // 本文のフォント(fontid.h)
@@ -3522,12 +3999,8 @@ void NodeTreeBase::check_fontid( const int number )
const std::string res_str = get_res_str( number );
JDLIB::Regex regex;
const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
- if( regex.exec( m_aa_regex, res_str, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.match( m_aa_regex, res_str, offset ) ){
fontid_mes = FONT_AA;
#ifdef _DEBUG
std::cout << "NodeTreeBase::check_fontid() fontid = " << FONT_AA
@@ -3559,55 +4032,52 @@ void NodeTreeBase::check_fontid( const int number )
//
bool NodeTreeBase::remove_imenu( char* str_link )
{
- char *p = str_link;
-
- if ( memcmp( p, "http", strlen( "http" ) ) != 0 ) return false;
- p += strlen( "http" );
- if ( *p == 's' ) p++;
- if ( memcmp( p, "://", strlen( "://" ) ) != 0 ) return false;
- p += strlen( "://" );
-
- const char *cut_sites[] = { "ime.nu/", "ime.st/", "nun.nu/", "pinktower.com/", 0 };
- const char **q = cut_sites;
- while ( *q ) {
- size_t cs_len = strlen( *q );
- if ( memcmp( p, *q, cs_len ) == 0 ) {
- // "http://ime.nu/"等、URLがそれだけだった場合は削除しない
- if ( p[cs_len] == '\0' ) return false;
- memmove( p, p + cs_len, strlen( p + cs_len ) + 1 );
- return true;
- }
- q ++;
- }
- return false;
-}
-
-
-// 文字列中の"&amp;"を"&"に変換する
-int NodeTreeBase::convert_amp( char* text, const int n )
-{
- int m = n;
-
- int i;
- for( i = 0; i < m; i++ ){
-
- if( text[ i ] == '&' &&
- m > (i + 4) &&
- text[i + 1] == 'a' &&
- text[i + 2] == 'm' &&
- text[i + 3] == 'p' &&
- text[i + 4] == ';' ){
-
- // &の次, &amp;の次, &amp;の次からの長さ
- memmove( text + i + 1, text + i + 5, n - i - 5 );
-
- // "amp;"の分減らす
- m -= 4;
+ int lng_cut = 4;
+ char *str_colon = str_link + lng_cut;
+ if( memcmp( str_link, "http", lng_cut ) == 0 ){
+ if( str_link[ lng_cut ] == 's' ){
+ lng_cut++;
+ str_colon++;
}
}
+ else return false;
- text[m] = '\0';
- return m;
+ if(
+ ! (
+ ( str_colon[ 3 ] == 'i' && str_colon[ 4 ] == 'm' )
+ || ( str_colon[ 3 ] == 'n' && str_colon[ 4 ] == 'u' )
+ || ( str_colon[ 3 ] == 'p' && str_colon[ 4 ] == 'i' )
+ || ( str_colon[ 3 ] == 'j' && str_colon[ 4 ] == 'u' )
+ )
+ ) return false;
+
+ if( memcmp( str_colon, "://ime.nu/", 10 ) == 0 ||
+ memcmp( str_colon, "://ime.st/", 10 ) == 0 ||
+ memcmp( str_colon, "://nun.nu/", 10 ) == 0 ){
+ lng_cut += 10;
+ }
+ else if( memcmp( str_colon, "://pinktower.com/", 17 ) == 0 ||
+ memcmp( str_colon, "://jump.2ch.net/?", 17 ) == 0 ||
+ memcmp( str_colon, "://jump.5ch.net/?", 17 ) == 0 ){
+ lng_cut += 17;
+ }
+ else return false;
+
+ int lng_link = strlen( str_link );
+
+ // "http://ime.nu/"等、URLがそれだけだった場合は削除しない
+ if( lng_link == lng_cut ) return false;
+
+ if( memcmp( str_link + lng_cut, "http", 4 ) == 0 ){
+ // プロトコルが続く場合は頭から削る
+ memmove( str_link, str_link + lng_cut, lng_link + 1 - lng_cut );
+ }
+ else{
+ // 上記以外はプロトコルを残して削る
+ memmove( str_colon + 3, str_link + lng_cut, lng_link + 1 - lng_cut );
+ }
+
+ return true;
}
diff --git a/src/dbtree/nodetreebase.h b/src/dbtree/nodetreebase.h
index ab771704..17d31ee8 100644
--- a/src/dbtree/nodetreebase.h
+++ b/src/dbtree/nodetreebase.h
@@ -13,6 +13,7 @@
#include "jdlib/heap.h"
#include "jdlib/miscutil.h"
+#include "jdlib/jdregex.h"
#include <map>
#include <cstring>
@@ -35,6 +36,8 @@ namespace DBTREE
constexpr size_t RESUME_CHKSIZE = 64;
+ struct IDHASH { const char *id; int num; IDHASH* child[2]; };
+
//ノードツリーのベースクラス
class NodeTreeBase : public SKELETON::Loadable
{
@@ -44,6 +47,7 @@ namespace DBTREE
SIG_UPDATED m_sig_finished;
std::string m_url;
+ std::string m_url_readcgi;
std::string m_default_noname;
// コード変換前の生データのサイズ ( byte )
@@ -82,19 +86,21 @@ namespace DBTREE
std::list< std::string > m_list_abone_id; // あぼーんするID
std::list< std::string > m_list_abone_name; // あぼーんする名前
std::list< std::string > m_list_abone_word; // あぼーんする文字列
- std::list< std::string > m_list_abone_regex; // あぼーんする正規表現
+ std::list< JDLIB::RegexPattern > m_list_abone_regex; // あぼーんする正規表現
std::list< std::string > m_list_abone_id_board; // あぼーんするID(板レベル)
std::list< std::string > m_list_abone_name_board; // あぼーんする名前(板レベル)
std::list< std::string > m_list_abone_word_board; // あぼーんする文字列(板レベル)
- std::list< std::string > m_list_abone_regex_board; // あぼーんする正規表現(板レベル)
+ std::list< JDLIB::RegexPattern > m_list_abone_regex_board; // あぼーんする正規表現(板レベル)
std::list< std::string > m_list_abone_word_global; // あぼーんする文字列(全体)
- std::list< std::string > m_list_abone_regex_global; // あぼーんする正規表現(全体)
+ std::list< JDLIB::RegexPattern > m_list_abone_regex_global; // あぼーんする正規表現(全体)
std::unordered_set< int > m_abone_reses; // レスあぼーん情報
bool m_abone_transparent; // 透明あぼーん
bool m_abone_chain; // 連鎖あぼーん
bool m_abone_age; // age ているレスはあぼーん
+ bool m_abone_default_name; // デフォルト名無しのレスはあぼーん
+ bool m_abone_noid; // ID無しのレスはあぼーん
bool m_abone_board; // 板レベルでのあぼーんを有効にする
bool m_abone_global; // 全体レベルでのあぼーんを有効にする
@@ -124,13 +130,13 @@ namespace DBTREE
NODE* m_node_previous;
// AA判定用
- std::string m_aa_regex;
+ JDLIB::RegexPattern m_aa_regex;
// その他のエラーメッセージ
std::string m_ext_err;
- // 各IDと発言数、レス番号のマッピング
- std::unordered_map< std::string, std::unordered_set< int > > m_map_id_name_resnumber;
+ // IDのハッシュテーブル
+ IDHASH **m_idhash;
protected:
@@ -161,6 +167,8 @@ namespace DBTREE
const std::string& get_ext_err() const { return m_ext_err; }
bool is_checking_update() const { return m_check_update; }
+ virtual int get_res_number_max(){ return -1; }
+
// number番のレスのヘッダノードのポインタを返す
NODE* res_header( int number );
@@ -199,7 +207,7 @@ namespace DBTREE
std::list< int > get_res_with_url();
// 含まれる URL をリストにして取得
- std::list< std::string > get_urls();
+ const std::list< std::string > get_imglinks();
// number番のレスを参照しているレス番号をリストにして取得
std::list< int > get_res_reference( const int number );
@@ -216,9 +224,6 @@ namespace DBTREE
// ref == true なら先頭に ">" を付ける
std::string get_res_str( int number, bool ref = false );
- // number 番のレスの生文字列を返す
- std::string get_raw_res_str( int number );
-
// 明示的にhtml を加える
// パースして追加したノードのポインタを返す
// html は UTF-8 であること
@@ -243,6 +248,7 @@ namespace DBTREE
const std::list< std::string >& list_abone_regex,
const std::unordered_set< int >& abone_reses,
const bool abone_transparent, const bool abone_chain, const bool abone_age,
+ const bool abone_default_name, const bool abone_noid,
const bool abone_board, const bool abone_global );
// 全レスのあぼーん状態の更新
@@ -272,7 +278,7 @@ namespace DBTREE
// 保存前にrawデータを加工
// デフォルトでは何もしない
- virtual char* process_raw_lines( char* rawlines ){ return rawlines; }
+ virtual char* process_raw_lines( char* rawlines, size_t& size ){ return rawlines; }
// raw データを dat に変換
// デフォルトでは何もしない
@@ -283,6 +289,10 @@ namespace DBTREE
void receive_data( const char* data, size_t size ) override;
void receive_finish() override;
+ void sweep_buffer();
+
+ // 拡張属性を取り出す
+ virtual void parse_extattr( const char* str, const int lng ) {};
private:
@@ -292,21 +302,20 @@ namespace DBTREE
NODE* create_node_idnum();
NODE* create_node_br();
NODE* create_node_hr();
- NODE* create_node_space( const int type );
- NODE* create_node_multispace( const char* text, const int n );
- NODE* create_node_htab();
- NODE* create_node_link( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold );
+ NODE* create_node_space( const int type, const int bg );
+ NODE* create_node_multispace( const char* text, const int n, const int bg );
+ NODE* create_node_link( const char* text, const int n, const char* link, const int n_link, const int color_text, const int color_back, const bool bold );
NODE* create_node_anc( const char* text, const int n, const char* link, const int n_link,
const int color_text, const bool bold,
const ANCINFO* ancinfo, const int lng_ancinfo );
NODE* create_node_sssp( const char* link, const int n_link );
NODE* create_node_img( const char* text, const int n, const char* link, const int n_link, const int color_text, const bool bold );
NODE* create_node_text( const char* text, const int color_text, const bool bold = false );
- NODE* create_node_ntext( const char* text, const int n, const int color_text, const bool bold = false );
+ NODE* create_node_ntext( const char* text, const int n, const int color_text, const int color_back = 0, const bool bold = false );
NODE* create_node_thumbnail( const char* text, const int n, const char* link, const int n_link, const char* thumb, const int n_thumb, const int color_text, const bool bold );
// 以下、構文解析用関数
- void add_raw_lines( char* rawines, size_t size );
+ size_t add_raw_lines( char* rawines, size_t size );
const char* add_one_dat_line( const char* datline );
void parse_name( NODE* header, const char* str, const int lng, const int color_name );
@@ -325,9 +334,10 @@ namespace DBTREE
// m_buffer_write に作成した文字列をセットする
void parse_write( const char* str, const int lng, const int max_lng_write );
- bool check_anchor( const int mode, const char* str_in, int& n, char* str_out, char* str_link, int lng_link, ANCINFO* ancinfo );
- int check_link( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link );
- int check_link_impl( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link, const int linktype, const int delim_pos );
+ bool check_anchor( const int mode, const char* str_in, int& n,
+ char* str_out, char* str_link, int lng_link, ANCINFO* ancinfo );
+ int check_link( const char* str_in, int& lng_in, char* str_text, size_t& lng_text,
+ char* str_link, size_t& lng_link );
// レジューム時のチェックデータをキャッシュ
void set_resume_data( const char* data, size_t length );
@@ -374,8 +384,7 @@ namespace DBTREE
// 発言数( num_id_name )の更新
// IDノードの色も変更する
- void set_num_id_name( NODE* header, const int num_id_name );
-
+ void set_num_id_name( NODE* header, const int num_id_name, NODE* pre_id_name_header );
// from_number番から to_number 番までのレスのフォント判定を更新
void update_fontid( const int from_number, const int to_number );
@@ -386,26 +395,7 @@ namespace DBTREE
// http://ime.nu/ などをリンクから削除
bool remove_imenu( char* str_link );
-
- // 文字列中の"&amp;"を"&"に変換する
- int convert_amp( char* text, const int n );
};
-
-
- //
- // リンクが現れたかチェックして文字列を取得する関数
- // (引数の値は、check_link_impl()を見ること)
- //
- inline int NodeTreeBase::check_link( const char* str_in, const int lng_in, int& n_in, char* str_link, const int lng_link )
- {
- // http://, https://, ftp://, ttp(s)://, tp(s):// のチェック
- int delim_pos = 0;
- const int linktype = MISC::is_url_scheme( str_in, &delim_pos );
-
- if( linktype == MISC::SCHEME_NONE ) return linktype;
-
- return check_link_impl( str_in, lng_in, n_in, str_link, lng_link, linktype, delim_pos );
- }
}
#endif
diff --git a/src/dbtree/nodetreejbbs.cpp b/src/dbtree/nodetreejbbs.cpp
index 261da5d9..4f610917 100644
--- a/src/dbtree/nodetreejbbs.cpp
+++ b/src/dbtree/nodetreejbbs.cpp
@@ -7,13 +7,15 @@
#include "interface.h"
#include "jdlib/jdiconv.h"
+#include "jdlib/miscutil.h"
#include "jdlib/loaderdata.h"
#include "config/globalconf.h"
-#include "global.h"
+#include "httpcode.h"
+#include "session.h"
-#include <sstream>
+#include <strings.h>
#define APPEND_SECTION( num ) do {\
@@ -27,10 +29,18 @@ byte += lng_sec[ num ]; \
using namespace DBTREE;
+enum
+{
+ MODE_NORMAL = 0,
+ MODE_KAKO
+};
+
+
NodeTreeJBBS::NodeTreeJBBS( const std::string& url, const std::string& date_modified )
: NodeTreeBase( url, date_modified )
, m_iconv( NULL )
, m_decoded_lines( NULL )
+ , m_mode( MODE_NORMAL )
{
#ifdef _DEBUG
std::cout << "NodeTreeJBBS::NodeTreeJBBS url = " << get_url() << " modified = " << date_modified << std::endl;
@@ -44,7 +54,12 @@ NodeTreeJBBS::~NodeTreeJBBS()
std::cout << "NodeTreeJBBS::~NodeTreeJBBS : " << get_url() << std::endl;
#endif
- clear();
+ // iconv 削除
+ if( m_iconv ) delete m_iconv;
+ m_iconv = NULL;
+
+ if( m_decoded_lines ) free( m_decoded_lines );
+ m_decoded_lines = NULL;
}
@@ -80,8 +95,7 @@ void NodeTreeJBBS::init_loading()
NodeTreeBase::init_loading();
// iconv 初期化
- std::string charset = DBTREE::board_charset( get_url() );
- if( ! m_iconv ) m_iconv = new JDLIB::Iconv( charset, "UTF-8" );
+ if( ! m_iconv ) m_iconv = new JDLIB::Iconv( DBTREE::article_charcode( get_url() ), CHARCODE_UTF8 );
if( ! m_decoded_lines ) m_decoded_lines = ( char* )malloc( BUF_SIZE_ICONV_OUT );
}
@@ -94,14 +108,13 @@ void NodeTreeJBBS::init_loading()
//
void NodeTreeJBBS::create_loaderdata( JDLIB::LOADERDATA& data )
{
- std::stringstream ss;
- ss << get_url() << "/";
+ if( m_mode == MODE_KAKO ) data.url = MISC::replace_str( get_url(), "rawmode", "read_archive" ) + "/";
+ else data.url = get_url() + "/";
+ if( id_header() ) data.url += MISC::itostr( id_header() + 1 ) + "-";
- // レジュームはしない代わりにスレを直接指定
+ // レジュームはしない
set_resume( false );
- if( id_header() ) ss << id_header() + 1 << "-";
- data.url = ss.str();
data.agent = DBTREE::get_agent( get_url() );
data.host_proxy = DBTREE::get_proxy_host( get_url() );
data.port_proxy = DBTREE::get_proxy_port( get_url() );
@@ -117,6 +130,52 @@ void NodeTreeJBBS::create_loaderdata( JDLIB::LOADERDATA& data )
}
+//
+// キャッシュに保存する前の前処理
+//
+char* NodeTreeJBBS::process_raw_lines( char* rawlines, size_t& size )
+{
+ if( m_mode == MODE_KAKO ) html2dat( rawlines );
+
+ return rawlines;
+}
+
+
+//
+// ロード完了
+//
+void NodeTreeJBBS::receive_finish()
+{
+#ifdef _DEBUG
+ std::cout << "NodeTreeJBBS::receive_finish : " << get_url() << std::endl
+ << "mode = " << m_mode << " code = " << get_code() << std::endl;
+#endif
+
+ // 更新チェックではない、オンラインの場合はログ倉庫から取得出来るか試みる
+ if( ! is_checking_update() && SESSION::is_online()
+ && m_mode == MODE_NORMAL && get_error() == "STORAGE IN" ){
+
+ m_mode = MODE_KAKO;
+#ifdef _DEBUG
+ std::cout << "switch mode to " << m_mode << std::endl;
+#endif
+ set_date_modified( std::string() );
+ download_dat( false );
+ return;
+ }
+
+ if( ! get_error().empty() ) set_str_code( get_error() );
+
+ // 過去ログから読み込んだ場合は DAT 落ちにする
+ if( m_mode != MODE_NORMAL ){
+ set_code( HTTP_OLD );
+ }
+
+ NodeTreeBase::receive_finish();
+ m_mode = MODE_NORMAL;
+}
+
+
//
// raw データを dat 形式に変換
//
@@ -260,3 +319,165 @@ const char* NodeTreeJBBS::raw2dat( char* rawlines, int& byte )
return m_decoded_lines;
}
+
+
+void NodeTreeJBBS::html2dat( char* lines )
+{
+ char* ps( lines );
+ char* pd( lines );
+ char* nextline( lines );
+ char* pos;
+ std::string title;
+ int num_next = id_header() + 1;
+
+ while( (pos = strchr( nextline, '\n' ) ) != NULL ){
+ *pos = '\0';
+ ps = nextline;
+ nextline = pos + 1;
+ if( ( pos = strstr( ps, "<dt><a name=\"" ) ) == NULL ){
+ if( ( pos = strstr( ps, "<title>" ) ) != NULL ){
+ // title
+ pos += 7;
+ char* epos;
+ if( ( epos = strstr( pos, "</title>" ) ) != NULL )
+ title.assign( pos, epos - pos );
+ }
+ }
+ else{
+ int num;
+ pos += 13;
+
+ // number
+ while( *pos != '>' && *pos != '\0' ) ++pos;
+ if( *pos == '\0' ) continue;
+ ps = pos + 1;
+ pos = strstr( ps, "</a>" );
+ if( pos == NULL || *pos == '\0' ) continue;
+ *pos = '\0';
+ num = atoi( ps );
+
+ // 既に読み込んでいる場合は飛ばす
+ if( num < num_next ) continue;
+
+ while( ps != pos ) *(pd++) = *(ps++);
+ if( *( pd - 1 ) == ' ' ) --pd;
+ *(pd++) = '<'; *(pd++) = '>';
+ pos += 4;
+ while( *pos != '<' && *pos != '\0' ) ++pos;
+ if( pos == NULL || *pos == '\0' ) continue;
+ ps = pos;
+
+ // mail
+ std::string mail;
+ if( memcmp( ps, "<a href=\"mailto:", 16 ) == 0 ){
+ pos = ps + 16;
+ while( *pos != '\"' && *pos != '\0' ) mail.push_back( *pos++ );
+ if( *pos == '\0' ) continue;
+ while( *pos != '>' && *pos != '\0' ) ++pos;
+ if( *pos == '\0' ) continue;
+ else ++pos;
+ ps = pos;
+ }
+
+ char* body;
+ if( ( body = strstr( ps, "<dd>" ) ) == NULL ) continue;
+ else *body = '\0';
+
+ // name
+ if( memcmp( ps, "<font color=\"#008800\">", 22 ) == 0 ) ps += 22;
+ if( memcmp( ps, "<b>", 3 ) == 0 ) ps += 3;
+ pos = body;
+ while( pos != ps && !( *pos == '\241' && *( pos + 1 ) == '\247' ) ) --pos;
+ if( pos == ps ) continue;
+ char* date = pos + 2;
+ while( pos != ps && !( *pos == ' ' && *( pos + 1 ) == '\305'
+ && *( pos + 2 ) == '\352' ) ) --pos;
+ if( pos == ps ) pos = date - 2;
+ if( *ps == ' ' ) ++ps;
+ memmove( pd, ps, pos - ps ); pd += pos - ps;
+ if( strncasecmp( pd - 7, "</font>", 7 ) == 0 ) pd -= 7;
+ if( strncasecmp( pd - 4, "</a>", 4 ) == 0 ) pd -= 4;
+ if( strncasecmp( pd - 4, "</b>", 4 ) == 0 ) pd -= 4;
+ if( *( pd - 1 ) == ' ' ) --pd;
+ *(pd++) = '<'; *(pd++) = '>';
+ mail.copy( pd, mail.length() );
+ pd += mail.length();
+ *(pd++) = '<'; *(pd++) = '>';
+ ps = date;
+ if( *ps == ' ' ) ++ps;
+
+ // date
+ pos = strstr( ps, " ID:" );
+ if( pos == NULL ) pos = strstr( ps, " <!--" );
+ if( pos == NULL || *pos == '\0' ) pos = body;
+ memmove( pd, ps, pos - ps );
+ pd += pos - ps;
+ if( *( pd - 1 ) == ' ' ) --pd;
+ if( strncasecmp( pd - 4, "<br>", 4 ) == 0 ) pd -= 4;
+ *(pd++) = '<'; *(pd++) = '>';
+
+ // id
+ std::string id;
+ if( pos != body ){
+ pos += 4;
+ if( *pos == '-' ) pos += 4;
+ ps = pos;
+ while( *pos != ' ' && *pos != '\0' ) ++pos;
+ *pos = '\0';
+ id = ps;
+ if( *id.end() == ' ' ) id.resize( id.size() - 1 );
+ }
+ ps = body + 4;
+ if( *ps == ' ' ) ++ps;
+
+ // message
+ while( ( pos = strchr( ps, '<' ) ) != NULL ){
+
+ if( pos != ps ){
+ memmove( pd, ps, pos - ps );
+ pd += pos - ps;
+ ps = pos;
+ }
+
+ else if( ( memcmp( ps, "<a href=\"", 9 ) == 0 )
+ && ( *( ps + 9 ) != '.' && *( ps + 9 ) != '/' ) ){
+ // 外部リンクのURL
+ if( ( pos = strchr( ps + 9, '>' ) ) != NULL ){
+ ps = pos + 1;
+ if( ( pos = strstr( ps, "</a>" ) ) != NULL ){
+ memmove( pd, ps, pos - ps );
+ pd += pos - ps;
+ ps = pos + 4;
+ }
+ }
+ }
+
+ else {
+ *(pd++) = '<';
+ ps += 1;
+ }
+ }
+
+ pos = ps;
+ while( *pos != '\0' ) *(pd++) = *(pos++);
+ if( memcmp( pd - 8, "<br><br>", 8 ) == 0 ) pd -= 8;
+ if( *( pd - 1 ) == ' ' ) --pd;
+ *(pd++) = '<'; *(pd++) = '>';
+
+ if( num == 1 ){
+ title.copy( pd, title.length() );
+ pd += title.length();
+ }
+ *(pd++) = '<'; *(pd++) = '>';
+
+ if( ! id.empty() ){
+ id.copy( pd, id.length() );
+ pd += id.length();
+ }
+
+ *(pd++) = '\n';
+ num_next = num + 1;
+ }
+ }
+ *pd = '\0';
+}
diff --git a/src/dbtree/nodetreejbbs.h b/src/dbtree/nodetreejbbs.h
index 09aa8b8f..e6f3c0b9 100644
--- a/src/dbtree/nodetreejbbs.h
+++ b/src/dbtree/nodetreejbbs.h
@@ -21,6 +21,7 @@ namespace DBTREE
{
JDLIB::Iconv* m_iconv;
char* m_decoded_lines;
+ int m_mode; // 読み込みモード
public:
@@ -32,7 +33,13 @@ namespace DBTREE
void clear() override;
void init_loading() override;
void create_loaderdata( JDLIB::LOADERDATA& data ) override;
+ char* process_raw_lines( char* rawlines, size_t& size ) override;
const char* raw2dat( char* rawlines, int& byte ) override;
+
+ private:
+
+ void receive_finish() override;
+ void html2dat( char* lines );
};
}
diff --git a/src/dbtree/nodetreemachi.cpp b/src/dbtree/nodetreemachi.cpp
index 603a79a0..eb170a3d 100644
--- a/src/dbtree/nodetreemachi.cpp
+++ b/src/dbtree/nodetreemachi.cpp
@@ -9,6 +9,7 @@
#include "jdlib/jdiconv.h"
#include "jdlib/jdregex.h"
#include "jdlib/loaderdata.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/miscmsg.h"
@@ -95,8 +96,7 @@ void NodeTreeMachi::init_loading()
if( ! m_regex ) m_regex = new JDLIB::Regex();
// iconv 初期化
- std::string charset = DBTREE::board_charset( get_url() );
- if( ! m_iconv ) m_iconv = new JDLIB::Iconv( charset, "UTF-8" );
+ if( ! m_iconv ) m_iconv = new JDLIB::Iconv( DBTREE::article_charcode( get_url() ), CHARCODE_UTF8 );
if( ! m_decoded_lines ) m_decoded_lines = ( char* )malloc( BUF_SIZE_ICONV_OUT );
if( ! m_buffer ) m_buffer = ( char* )malloc( BUF_SIZE_ICONV_OUT + 64 );
@@ -160,7 +160,7 @@ void NodeTreeMachi::create_loaderdata( JDLIB::LOADERDATA& data )
//
// キャッシュに保存する前の前処理
//
-char* NodeTreeMachi::process_raw_lines( char* rawlines )
+char* NodeTreeMachi::process_raw_lines( char* rawlines, size_t& size )
{
// オフラインか offlaw 形式を使用する場合はそのまま返す
if( ! is_loading() || CONFIG::get_use_machi_offlaw() ) return rawlines;
@@ -205,10 +205,9 @@ char* NodeTreeMachi::process_raw_lines( char* rawlines )
std::string reg_subject( "<title>([^<]*)</title>" );
if( m_regex->exec( reg_subject, line, offset, icase, newline, usemigemo, wchar ) ){
- const std::string charset = DBTREE::board_charset( get_url() );
- m_subject_machi = MISC::Iconv( m_regex->str( 1 ), charset, "UTF-8" );
+ m_subject_machi = MISC::Iconv( m_regex->str( 1 ), get_charcode(), CHARCODE_UTF8 );
#ifdef _DEBUG
- std::cout << "NodeTreeMachi::process_raw_lines\n";
+ std::cout << "NodeTreeMachi::process_raw_lines" << std::endl;
std::cout << "subject = " << m_subject_machi << std::endl;
#endif
}
@@ -301,7 +300,7 @@ const char* NodeTreeMachi::raw2dat( char* rawlines, int& byte )
// read.cgi 形式
else{
- std::string reg( "<dt>([1-9][0-9]*) ?名前:(<a href=\"mailto:([^\"]*)\"><b>|<font[^>]*><b>) ?(<font[^>]*>)?([^<]*)(</font>)? ?</[bB]>.+ ?投稿日: ?([^<]*)( <font[^>]*>\\[ ?(.*) ?\\]</font>)?<br><dd> ?(.*) ?<br><br>$" );
+ std::string reg( "<dt>([1-9][0-9]*) ?名前:(<a href=\"mailto:([^\"]*)\"><b>|<font[^>]*><b>) ?(<font[^>]*>)?([^<]*)(</font>)? ?</[bB]>.+ ?投稿日: ?([^<]*)( <font[^>]*>\\[ ?(.*) ?\\]</font>)?<br><dd> ?(.*) ?<br><br>(<script [^>]+>)?$" );
if( ! m_regex->exec( reg, line, offset, icase, newline, usemigemo, wchar ) ){
#ifdef _DEBUG
diff --git a/src/dbtree/nodetreemachi.h b/src/dbtree/nodetreemachi.h
index c52dedb9..59fcd391 100644
--- a/src/dbtree/nodetreemachi.h
+++ b/src/dbtree/nodetreemachi.h
@@ -40,7 +40,7 @@ namespace DBTREE
void clear() override;
void init_loading() override;
void create_loaderdata( JDLIB::LOADERDATA& data ) override;
- char* process_raw_lines( char* rawlines ) override;
+ char* process_raw_lines( char* rawlines, size_t& size ) override;
const char* raw2dat( char* rawlines, int& byte ) override;
void receive_data( const char* data, size_t size ) override;
diff --git a/src/dbtree/root.cpp b/src/dbtree/root.cpp
index 86b8913d..86c5587e 100644
--- a/src/dbtree/root.cpp
+++ b/src/dbtree/root.cpp
@@ -168,17 +168,14 @@ BoardBase* Root::get_board( const std::string& url, const int count )
if( count == 0 ){
size_t pos = url.rfind( "http://" );
+ size_t pos2 = url.rfind( "https://" );
// ユーザープロフィールアドレス( http://be.2ch.net/test/p.php?u=d:http://〜 )の様に
// 先頭以外に http:// が入っている場合は失敗
- if( pos != std::string::npos && pos != 0 ) return m_board_null;
+ if( ( pos != std::string::npos && pos != 0 ) || ( pos2 != std::string::npos && pos2 != 0 ) ) return m_board_null;
- size_t pos2 = url.rfind( "https://" );
- if ( pos2 != std::string::npos && pos2 != 0 ) return m_board_null;
- if ( pos2 == 0 ) pos = 0;
-
- // http[s]:// が含まれていなかったら先頭に追加して再帰呼び出し
- if( pos == std::string::npos && ! is_local( url ) ){
+ // http:// が含まれていなかったら先頭に追加して再帰呼び出し
+ else if( pos == std::string::npos && pos2 == std::string::npos && ! is_local( url ) ){
BoardBase* board = get_board( "http://" + url , count + 1 );
m_get_board_url = url;
return board;
@@ -277,12 +274,7 @@ void Root::load_cache()
{
clear();
- // ファイルが存在しなければ入力を旧ファイル名にする
std::string file_in = CACHE::path_xml_listmain();
- if( CACHE::file_exists( file_in ) != CACHE::EXIST_FILE )
- {
- file_in = CACHE::path_xml_listmain_old();
- }
#ifdef _DEBUG
std::cout << "Root::load_cache xml = " << file_in << std::endl;
@@ -369,7 +361,7 @@ void Root::receive_finish()
}
// 文字コードを変換してXML作成
- JDLIB::Iconv* libiconv = new JDLIB::Iconv( "MS932", "UTF-8" );
+ JDLIB::Iconv* libiconv = new JDLIB::Iconv( CHARCODE_SJIS, CHARCODE_UTF8 );
int byte_out;
const char* rawdata_utf8 = libiconv->convert( m_rawdata , m_lng_rawdata, byte_out );
bbsmenu2xml( rawdata_utf8 );
@@ -422,13 +414,14 @@ void Root::bbsmenu2xml( const std::string& menu )
// 現在の仕様では HTML > BODY > font[size="2"] の子要素が対象
XML::DomList targets = html.getElementsByTagName( "font" )[0]->childNodes();
+ if( targets.empty() ) targets = html.getElementsByTagName( "small" )[0]->childNodes();
std::list< XML::Dom* >::iterator it = targets.begin();
while( it != targets.end() )
{
// 要素b( カテゴリ名 )
if( (*it)->nodeName() == "b" )
{
- const std::string category = (*it)->firstChild()->nodeValue();
+ const std::string category = MISC::chref_decode( (*it)->firstChild()->nodeValue() );
// 追加しないカテゴリ
if( category == "チャット"
@@ -448,13 +441,13 @@ void Root::bbsmenu2xml( const std::string& menu )
// 要素bに続く要素a( 板URL )
else if( subdir && enabled && (*it)->nodeName() == "a" )
{
- const std::string board_name = (*it)->firstChild()->nodeValue();
+ const std::string board_name = MISC::chref_decode( (*it)->firstChild()->nodeValue() );
const std::string url = (*it)->getAttribute( "href" );
// 板として扱うURLかどうかで要素名を変える
std::string element_name;
if( CONFIG::use_link_as_board() ) element_name = "board";
- else if( ( regex.exec( "^https?://.*/.*/$", url, offset, icase, newline, usemigemo, wchar )
+ else if( ( regex.exec( "^(https?:)?//.*/.*/$", url, offset, icase, newline, usemigemo, wchar )
&& ( is_2ch( url ) || is_machi( url ) ) )
|| is_JBBS( url )
|| is_vip2ch( url )
@@ -545,11 +538,11 @@ int Root::get_board_type( const std::string& url, std::string& root, std::string
int type = TYPE_BOARD_UNKNOWN;
// 2ch
- if( ! etc && is_2ch( url ) ){
+ if( /*! etc &&*/ is_2ch( url ) ){
- if( regex.exec( "(https?://[^/]*)/([^/]*)/$" , url, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.exec( "(https?://[^/]*)(/[^/]*)/$" , url, offset, icase, newline, usemigemo, wchar ) ){
root = regex.str( 1 );
- path_board = "/" + regex.str( 2 );
+ path_board = regex.str( 2 );
type = TYPE_BOARD_2CH;
}
@@ -558,9 +551,9 @@ int Root::get_board_type( const std::string& url, std::string& root, std::string
// JBBS
else if( is_JBBS( url ) ){
- if( regex.exec( "(https?://[^/]*)/(.*)/(index2?\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){
- root = regex.str( 1 );
- path_board = "/" + regex.str( 2 );
+ if( regex.exec( "(https?://)[^/]*(/.*)/(index2?\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){
+ root = regex.str( 1 ) + "jbbs.shitaraba.net";
+ path_board = regex.str( 2 );
type = TYPE_BOARD_JBBS;
}
@@ -569,9 +562,9 @@ int Root::get_board_type( const std::string& url, std::string& root, std::string
// まち
else if( is_machi( url ) ){
- if( regex.exec( "(https?://[^/]*)/([^/]*)/(index2?\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.exec( "(https?://[^/]*)(/[^/]*)/(index2?\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){
root = regex.str( 1 );
- path_board = "/" + regex.str( 2 );
+ path_board = regex.str( 2 );
type = TYPE_BOARD_MACHI;
}
@@ -580,9 +573,9 @@ int Root::get_board_type( const std::string& url, std::string& root, std::string
// vipサービス
else if( is_vip2ch( url ) ){
- if( regex.exec( "(https?://[^/]*)/([^/]*)/$" , url, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.exec( "(https?://[^/]*)(/[^/]*)/$" , url, offset, icase, newline, usemigemo, wchar ) ){
root = regex.str( 1 );
- path_board = "/" + regex.str( 2 );
+ path_board = regex.str( 2 );
type = TYPE_BOARD_2CH_COMPATI;
}
@@ -591,7 +584,7 @@ int Root::get_board_type( const std::string& url, std::string& root, std::string
// ローカルファイル
else if( is_local( url ) ){
- root = URL_BOARD_LOCAL;
+ root = "file://";
path_board = "/local";
type = TYPE_BOARD_LOCAL;
@@ -600,9 +593,9 @@ int Root::get_board_type( const std::string& url, std::string& root, std::string
// その他は互換型
else{
- if( regex.exec( "(https?://.*)/([^/]*)/([^\\.]+\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.exec( "(https?://.*)(/[^/]*)/([^\\.]+\\.html?)?$" , url, offset, icase, newline, usemigemo, wchar ) ){
root = regex.str( 1 );
- path_board = "/" + regex.str( 2 );
+ path_board = regex.str( 2 );
type = TYPE_BOARD_2CH_COMPATI;
}
@@ -622,7 +615,7 @@ int Root::get_board_type( const std::string& root, const bool etc ){
int type = TYPE_BOARD_UNKNOWN;
// 2ch
- if( ! etc && is_2ch( root ) )
+ if( /*! etc &&*/ is_2ch( root ) )
type = TYPE_BOARD_2CH;
// JBBS
@@ -657,11 +650,20 @@ bool Root::set_board( const std::string& url, const std::string& name, const std
std::cout << "Root::set_board " << url << " " << name << std::endl;
#endif
+ std::string real_url;
std::string root;
std::string path_board;
+ // scheme省略の場合は補う
+ if( url.compare( 0, 2, "//" ) == 0 ){
+ std::string menu_url = CONFIG::get_url_bbsmenu();
+ size_t pos = menu_url.find("://");
+ if( pos != std::string::npos ) real_url = menu_url.substr( 0, pos + 1 );
+ }
+ real_url += url;
+
// タイプ判定
- int type = get_board_type( url, root, path_board, etc );
+ int type = get_board_type( real_url, root, path_board, etc );
if( type == TYPE_BOARD_UNKNOWN ) return false;
// 移転チェック
@@ -697,7 +699,7 @@ bool Root::set_board( const std::string& url, const std::string& name, const std
MISC::ERRMSG( tmp_msg );
const std::string path1 = CACHE::path_board_root_fast( board->url_boardbase() );
- const std::string path2 = CACHE::path_board_root_fast( url );
+ const std::string path2 = CACHE::path_board_root_fast( real_url );
#ifdef _DEBUG
std::cout << "path1 = " << path1 << std::endl
@@ -836,19 +838,22 @@ bool Root::exec_move_board( BoardBase* board,
// キャッシュがある場合はダイアログに表示
m_move_info += ss.str() + "\n";
- // 移動先に同名のファイルかフォルダ何かあったらリネームしてバックアップをとっておく
- if( CACHE::file_exists( new_path ) != CACHE::EXIST_ERROR ){
+ if( new_path != old_path ){
- std::string path_tmp = new_path.substr( 0, new_path.length() - 1 ) + "_bk/";
- if( rename( new_path.c_str(), path_tmp.c_str() ) == 0 ) MISC::MSG( "rename : " + new_path + " -> " + path_tmp );
- else MISC::ERRMSG( "can't rename " + new_path + " to " + path_tmp );
- }
+ // 移動先に同名のファイルかフォルダ何かあったらリネームしてバックアップをとっておく
+ if( CACHE::file_exists( new_path ) != CACHE::EXIST_ERROR ){
- // キャッシュ移動
- if( CACHE::mkdir_parent_of_board( new_url ) ){
+ std::string path_tmp = new_path.substr( 0, new_path.length() - 1 ) + "_bk/";
+ if( rename( new_path.c_str(), path_tmp.c_str() ) == 0 ) MISC::MSG( "rename : " + new_path + " -> " + path_tmp );
+ else MISC::ERRMSG( "can't rename " + new_path + " to " + path_tmp );
+ }
- if( rename( old_path.c_str(), new_path.c_str() ) == 0 ) MISC::MSG( "cache was moved : " + old_path + " -> " + new_path );
- else MISC::ERRMSG( "can't move cache from " + old_path + " to " + new_path );
+ // キャッシュ移動
+ if( CACHE::mkdir_parent_of_board( new_url ) ){
+
+ if( rename( old_path.c_str(), new_path.c_str() ) == 0 ) MISC::MSG( "cache was moved : " + old_path + " -> " + new_path );
+ else MISC::ERRMSG( "can't move cache from " + old_path + " to " + new_path );
+ }
}
#ifdef _DEBUG
@@ -1078,10 +1083,10 @@ void Root::load_etc()
if( it == list_etc.end() ) break;
// basic認証
- if( regex.exec( "https?://([^/]+:[^/]+@)(.+)$" , info.url, offset, icase, newline, usemigemo, wchar ) )
+ if( regex.exec( "(https?://)([^/]+:[^/]+@)(.+)$" , info.url, offset, icase, newline, usemigemo, wchar ) )
{
- info.basicauth = regex.str( 1 ).substr( 0, regex.str( 1 ).length() - 1 );
- info.url = ( info.url[4] == 's' ? "https://" : "http://" ) + regex.str( 2 );
+ info.basicauth = regex.str( 2 ).substr( 0, regex.str( 2 ).length() - 1 );
+ info.url = regex.str( 1 ) + regex.str( 3 );
}
// board id
diff --git a/src/dbtree/ruleloader.cpp b/src/dbtree/ruleloader.cpp
index c07339db..29d71eaa 100644
--- a/src/dbtree/ruleloader.cpp
+++ b/src/dbtree/ruleloader.cpp
@@ -49,12 +49,6 @@ std::string RuleLoader::get_path()
}
-std::string RuleLoader::get_charset()
-{
- return DBTREE::board_charset( m_url_boadbase );
-}
-
-
// ロード用データ作成
void RuleLoader::create_loaderdata( JDLIB::LOADERDATA& data )
{
diff --git a/src/dbtree/ruleloader.h b/src/dbtree/ruleloader.h
index 81765b95..c44467fe 100644
--- a/src/dbtree/ruleloader.h
+++ b/src/dbtree/ruleloader.h
@@ -30,7 +30,6 @@ namespace DBTREE
std::string get_url() override;
std::string get_path() override;
- std::string get_charset() override;
// ロード用データ作成
void create_loaderdata( JDLIB::LOADERDATA& data ) override;
diff --git a/src/dbtree/settingloader.cpp b/src/dbtree/settingloader.cpp
index c4ef9baf..d3419b3f 100644
--- a/src/dbtree/settingloader.cpp
+++ b/src/dbtree/settingloader.cpp
@@ -12,8 +12,7 @@
#include "config/globalconf.h"
#include "cache.h"
-
-#define SETTING_TXT "SETTING.TXT"
+#include "global.h"
using namespace DBTREE;
@@ -24,7 +23,7 @@ SettingLoader::SettingLoader( const std::string& url_boadbase )
m_message_count( 0 )
{
#ifdef _DEBUG
- std::cout << "SettingLoader::SettingLoader : " << get_url() << std::endl;
+ std::cout << "SettingLoader::SettingLoader : " << m_url_boadbase << std::endl;
#endif
set_date_modified( DBTREE::board_get_modified_setting( m_url_boadbase ) );
@@ -34,14 +33,14 @@ SettingLoader::SettingLoader( const std::string& url_boadbase )
SettingLoader::~SettingLoader()
{
#ifdef _DEBUG
- std::cout << "SettingLoader::~SettingLoader : " << get_url() << std::endl;
+ std::cout << "SettingLoader::~SettingLoader : " << m_url_boadbase << std::endl;
#endif
}
std::string SettingLoader::get_url()
{
- return m_url_boadbase + SETTING_TXT;
+ return DBTREE::url_settingtxt( m_url_boadbase );
}
@@ -51,12 +50,6 @@ std::string SettingLoader::get_path()
}
-std::string SettingLoader::get_charset()
-{
- return DBTREE::board_charset( m_url_boadbase );
-}
-
-
// ロード用データ作成
void SettingLoader::create_loaderdata( JDLIB::LOADERDATA& data )
{
@@ -89,6 +82,12 @@ void SettingLoader::parse_data()
m_line_number = cf.get_option_int( "BBS_LINE_NUMBER", 0, 0, 8192 );
m_message_count = cf.get_option_int( "BBS_MESSAGE_COUNT", 0, 0, 81920 );
m_unicode = cf.get_option_str( "BBS_UNICODE", "" );
+ const int num_thread_stop = cf.get_option_int( "BBS_THREAD_STOP", 0, 0, CONFIG::get_max_resnumber() );
+ if( num_thread_stop ){
+ const int max_res = DBTREE::board_get_number_max_res( m_url_boadbase );
+ if( ! max_res && max_res != num_thread_stop )
+ DBTREE::board_set_number_max_res( m_url_boadbase, num_thread_stop );
+ }
DBTREE::board_set_modified_setting( m_url_boadbase, get_date_modified() );
#ifdef _DEBUG
diff --git a/src/dbtree/settingloader.h b/src/dbtree/settingloader.h
index 179b3044..18fb64cd 100644
--- a/src/dbtree/settingloader.h
+++ b/src/dbtree/settingloader.h
@@ -10,6 +10,8 @@
#include <string>
+#define SETTING_TXT "SETTING.TXT"
+
namespace JDLIB
{
class LOADERDATA;
@@ -47,7 +49,6 @@ namespace DBTREE
std::string get_url() override;
std::string get_path() override;
- std::string get_charset() override;
// ロード用データ作成
void create_loaderdata( JDLIB::LOADERDATA& data ) override;
diff --git a/src/dbtree/spchar_decoder.cpp b/src/dbtree/spchar_decoder.cpp
index 46fede11..06b02f14 100644
--- a/src/dbtree/spchar_decoder.cpp
+++ b/src/dbtree/spchar_decoder.cpp
@@ -7,7 +7,9 @@
#include "spchar_tbl.h"
#include "node.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
+#include "config/globalconf.h"
#include <string.h>
#include <stdlib.h>
@@ -48,21 +50,58 @@ int decode_char_number( const char* in_char, int& n_in, char* out_char, int& n_
if( only_check ) return ret;
- const int num = MISC::decode_spchar_number( in_char, offset, lng );
+ int num = MISC::decode_spchar_number( in_char, offset, lng );
+
+ // 特殊条件を処理
+ if( num >= 0x80 && num <= 0x9F ) num = charref_tbl[ num - 0x80 ];
+ else if( num == 0 || num > 0x10FFFF ) num = UCS_REPLACE;
+ else if( num >= 0xD800 && num < 0xE000 ){
+
+ // 間違ったエンコードで壊れた追加面の文字を修復する
+ if( !CONFIG::get_correct_character_reference() ) num = UCS_REPLACE;
+ else {
+ const char *char_low = in_char + offset + lng + 1;
+ int offset_low;
+ int lng_low = MISC::spchar_number_ln( char_low, offset_low );
+ if( lng_low == -1 ) num = UCS_REPLACE;
+ else{
+ const int num_low = MISC::decode_spchar_number( char_low, offset_low, lng_low );
+ if( num < 0xDC01 && num_low >= 0xDC00 && num_low < 0xE000 ){
+ num = 0x10000 + ( num - 0xD800 ) * 0x400 + ( num_low - 0xDC00 );
+ offset += 1 + offset_low + lng_low;
+ }
+ else num = UCS_REPLACE;
+ }
+ }
+ }
switch( num ){
- //zwnj,zwj,lrm,rlm は今のところ無視(zwspにする)
+ //lfはspにする
+ case UCS_SP:
+ case UCS_LF:
+ ret = DBTREE::NODE_SP;
+ break;
+
+ case UCS_HT:
+ ret = DBTREE::NODE_HTAB;
+ break;
+
+ //zwnj,zwj,lrm,rlm,lre,rle,lro.rlo は今のところ無視
case UCS_ZWSP:
- case UCS_ZWNJ:
- case UCS_ZWJ:
- case UCS_LRM:
- case UCS_RLM:
+// case UCS_ZWNJ:
+// case UCS_ZWJ:
+// case UCS_LRM:
+// case UCS_RLM:
+ case UCS_CR: // CRを無視
+ case UCS_FF: // FFを無視
+ case UCS_LS: // LSを無視
+ case UCS_PS: // PSを無視
ret = DBTREE::NODE_ZWSP;
break;
default:
- n_out = MISC::ucs2toutf8( num, out_char );
+ n_out = MISC::cptoutf8( num, out_char );
if( ! n_out ) return DBTREE::NODE_NONE;
}
@@ -103,28 +142,25 @@ int DBTREE::decode_char( const char* in_char, int& n_in, char* out_char, int& n
int ret = DBTREE::NODE_TEXT;
n_in = n_out = 0;
- int i = 0;
- for(;;){
+ const char ch = in_char[ 1 ];
+ UCSTBL const *tbl;
- const int ucs = ucstbl[ i ].ucs;
- if( ! ucs ) break;
- if( in_char[ 1 ] == ucstbl[ i ].str[ 0 ] ){
+ if( ch >= 'a' && ch <= 'z' ) tbl = ucstbl_small[ ch - 'a' ];
+ else if( ch >= 'A' && ch <= 'Z' ) tbl = ucstbl_large[ ch - 'A' ];
+ else return DBTREE::NODE_NONE;
- if( check_spchar( in_char +1, ucstbl[ i ].str ) ){
+ for( int ucs = tbl->ucs; ucs != 0; ucs = ( ++tbl )->ucs ){
+ if( check_spchar( in_char + 1, tbl->str ) ){
- if( only_check ) return ret;
+ if( only_check ) return ret;
- n_in = strlen( ucstbl[ i ].str ) +1;
+ n_in = strlen( tbl->str ) + 1; // 先頭の '&' の分を+1する
- // zwnj, zwj, lrm, rlm は今のところ無視する(zwspにする)
- if( ucs >= UCS_ZWSP && ucs <= UCS_RLM ) ret = DBTREE::NODE_ZWSP;
- else n_out = MISC::ucs2toutf8( ucs, out_char );
+ if( ucs == UCS_ZWSP ) ret = DBTREE::NODE_ZWSP;
+ else n_out = MISC::cptoutf8( ucs, out_char );
- break;
- }
+ break;
}
-
- ++i;
}
if( !n_in ) ret = DBTREE::NODE_NONE;
diff --git a/src/dbtree/spchar_tbl.h b/src/dbtree/spchar_tbl.h
index e80b364e..1f4f3a88 100644
--- a/src/dbtree/spchar_tbl.h
+++ b/src/dbtree/spchar_tbl.h
@@ -8,282 +8,515 @@
struct UCSTBL
{
- int ucs;
- char str[ 256 ];
+ unsigned short ucs;
+ char str[ 12 ];
};
-UCSTBL ucstbl[] = {
+static UCSTBL const ucstbl_empty[] = {
+ { 0, "" }
+};
- { 34, "quot;" },
- { 38, "amp;" },
- { 60, "lt;" },
- { 62, "gt;" },
+static UCSTBL const ucstbl_a[] = {
+ { 38, "amp;" },
+ { 180, "acute;" },
+ { 224, "agrave;" },
+ { 225, "aacute;" },
+ { 226, "acirc;" },
+ { 227, "atilde;" },
+ { 228, "auml;" },
+ { 229, "aring;" },
+ { 230, "aelig;" },
+ { 945, "alpha;" },
+ { 8501, "alefsym;" },
+ { 8736, "ang;" },
+ { 8743, "and;" },
+ { 8776, "asymp;" },
+ { 0, "" }
+};
- { 32, "nbsp;" },
-// { 160, "nbsp;" }, // 正しくはこちら
+static UCSTBL const ucstbl_b[] = {
+ { 166, "brvbar;" },
+ { 946, "beta;" },
+ { 8222, "bdquo;" },
+ { 8226, "bull;" },
+ { 0, "" }
+};
- { 161, "iexcl;" },
- { 162, "cent;" },
- { 163, "pound;" },
- { 164, "curren;" },
- { 165, "yen;" },
- { 166, "brvbar;" },
- { 167, "sect;" },
- { 168, "uml;" },
- { 169, "copy;" },
- { 170, "ordf;" },
- { 171, "laquo;" },
- { 172, "not;" },
- { 173, "shy;" },
- { 174, "reg;" },
- { 175, "macr;" },
- { 176, "deg;" },
- { 177, "plusmn;" },
- { 178, "sup2;" },
- { 179, "sup3;" },
- { 180, "acute;" },
- { 181, "micro;" },
- { 182, "para;" },
- { 183, "middot;" },
- { 184, "cedil;" },
- { 185, "sup1;" },
- { 186, "ordm;" },
- { 187, "raquo;" },
- { 188, "frac14;" },
- { 189, "frac12;" },
- { 190, "frac34;" },
- { 191, "iquest;" },
- { 192, "Agrave;" },
- { 193, "Aacute;" },
- { 194, "Acirc;" },
- { 195, "Atilde;" },
- { 196, "Auml;" },
- { 197, "Aring;" },
- { 198, "AElig;" },
- { 199, "Ccedil;" },
- { 200, "Egrave;" },
- { 201, "Eacute;" },
- { 202, "Ecirc;" },
- { 203, "Euml;" },
- { 204, "Igrave;" },
- { 205, "Iacute;" },
- { 206, "Icirc;" },
- { 207, "Iuml;" },
- { 208, "ETH;" },
- { 209, "Ntilde;" },
- { 210, "Ograve;" },
- { 211, "Oacute;" },
- { 212, "Ocirc;" },
- { 213, "Otilde;" },
- { 214, "Ouml;" },
- { 215, "times;" },
- { 216, "Oslash;" },
- { 217, "Ugrave;" },
- { 218, "Uacute;" },
- { 219, "Ucirc;" },
- { 220, "Uuml;" },
- { 221, "Yacute;" },
- { 222, "THORN;" },
- { 223, "szlig;" },
- { 224, "agrave;" },
- { 225, "aacute;" },
- { 226, "acirc;" },
- { 227, "atilde;" },
- { 228, "auml;" },
- { 229, "aring;" },
- { 230, "aelig;" },
- { 231, "ccedil;" },
- { 232, "egrave;" },
- { 233, "eacute;" },
- { 234, "ecirc;" },
- { 235, "euml;" },
- { 236, "igrave;" },
- { 237, "iacute;" },
- { 238, "icirc;" },
- { 239, "iuml;" },
- { 240, "eth;" },
- { 241, "ntilde;" },
- { 242, "ograve;" },
- { 243, "oacute;" },
- { 244, "ocirc;" },
- { 245, "otilde;" },
- { 246, "ouml;" },
- { 247, "divide;" },
- { 248, "oslash;" },
- { 249, "ugrave;" },
- { 250, "uacute;" },
- { 251, "ucirc;" },
- { 252, "uuml;" },
- { 253, "yacute;" },
- { 254, "thorn;" },
- { 255, "yuml;" },
- { 338, "OElig;" },
- { 339, "oelig;" },
- { 352, "Scaron;" },
- { 353, "scaron;" },
- { 376, "Yuml;" },
- { 402, "fnof;" },
- { 710, "circ;" },
- { 732, "tilde;" },
- { 913, "Alpha;" },
- { 914, "Beta;" },
- { 915, "Gamma;" },
- { 916, "Delta;" },
- { 917, "Epsilon;" },
- { 918, "Zeta;" },
- { 919, "Eta;" },
- { 920, "Theta;" },
- { 921, "Iota;" },
- { 922, "Kappa;" },
- { 923, "Lambda;" },
- { 924, "Mu;" },
- { 925, "Nu;" },
- { 926, "Xi;" },
- { 927, "Omicron;" },
- { 928, "Pi;" },
- { 929, "Rho;" },
- { 931, "Sigma;" },
- { 932, "Tau;" },
- { 933, "Upsilon;" },
- { 934, "Phi;" },
- { 935, "Chi;" },
- { 936, "Psi;" },
- { 937, "Omega;" },
- { 945, "alpha;" },
- { 946, "beta;" },
- { 947, "gamma;" },
- { 948, "delta;" },
- { 949, "epsilon;" },
- { 950, "zeta;" },
- { 951, "eta;" },
- { 952, "theta;" },
- { 953, "iota;" },
- { 954, "kappa;" },
- { 955, "lambda;" },
- { 956, "mu;" },
- { 957, "nu;" },
- { 958, "xi;" },
- { 959, "omicron;" },
- { 960, "pi;" },
- { 961, "rho;" },
- { 962, "sigmaf;" },
- { 963, "sigma;" },
- { 964, "tau;" },
- { 965, "upsilon;" },
- { 966, "phi;" },
- { 967, "chi;" },
- { 968, "psi;" },
- { 969, "omega;" },
- { 977, "thetasym;" },
- { 978, "upsih;" },
- { 982, "piv;" },
+static UCSTBL const ucstbl_c[] = {
+ { 162, "cent;" },
+ { 164, "curren;" },
+ { 169, "copy;" },
+ { 184, "cedil;" },
+ { 231, "ccedil;" },
+ { 710, "circ;" },
+ { 967, "chi;" },
+ { 8629, "crarr;" },
+ { 8745, "cap;" },
+ { 8746, "cup;" },
+ { 8773, "cong;" },
+ { 9827, "clubs;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_d[] = {
+ { 176, "deg;" },
+ { 247, "divide;" },
+ { 948, "delta;" },
+ { 8224, "dagger;" },
+ { 8595, "darr;" },
+ { 8659, "dArr;" },
+ { 9830, "diams;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_e[] = {
+ { 232, "egrave;" },
+ { 233, "eacute;" },
+ { 234, "ecirc;" },
+ { 235, "euml;" },
+ { 240, "eth;" },
+ { 949, "epsilon;" },
+ { 951, "eta;" },
{ 8194, "ensp;" },
{ 8195, "emsp;" },
+ { 8364, "euro;" },
+ { 8707, "exist;" },
+ { 8709, "empty;" },
+ { 8801, "equiv;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_f[] = {
+ { 188, "frac14;" },
+ { 189, "frac12;" },
+ { 190, "frac34;" },
+ { 402, "fnof;" },
+ { 8260, "frasl;" },
+ { 8704, "forall;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_g[] = {
+ { 62, "gt;" },
+ { 947, "gamma;" },
+ { 8805, "ge;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_h[] = {
+ { 8230, "hellip;" },
+ { 8596, "harr;" },
+ { 8660, "hArr;" },
+ { 9829, "hearts;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_i[] = {
+ { 161, "iexcl;" },
+ { 191, "iquest;" },
+ { 236, "igrave;" },
+ { 237, "iacute;" },
+ { 238, "icirc;" },
+ { 239, "iuml;" },
+ { 953, "iota;" },
+ { 8465, "image;" },
+ { 8712, "isin;" },
+ { 8734, "infin;" },
+ { 8747, "int;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_k[] = {
+ { 954, "kappa;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_l[] = {
+ { 60, "lt;" },
+ { 171, "laquo;" },
+ { 955, "lambda;" },
+ { 8206, "lrm;" },
+ { 8216, "lsquo;" },
+ { 8220, "ldquo;" },
+ { 8249, "lsaquo;" },
+ { 8592, "larr;" },
+ { 8656, "lArr;" },
+ { 8727, "lowast;" },
+ { 8804, "le;" },
+ { 8968, "lceil;" },
+ { 8970, "lfloor;" },
+ { 9001, "lang;" },
+ { 9674, "loz;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_m[] = {
+ { 175, "macr;" },
+ { 181, "micro;" },
+ { 183, "middot;" },
+ { 956, "mu;" },
+ { 8212, "mdash;" },
+ { 8722, "minus;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_n[] = {
+ { 160, "nbsp;" },
+ { 172, "not;" },
+ { 241, "ntilde;" },
+ { 957, "nu;" },
+ { 8211, "ndash;" },
+ { 8711, "nabla;" },
+ { 8713, "notin;" },
+ { 8715, "ni;" },
+ { 8800, "ne;" },
+ { 8836, "nsub;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_o[] = {
+ { 170, "ordf;" },
+ { 186, "ordm;" },
+ { 242, "ograve;" },
+ { 243, "oacute;" },
+ { 244, "ocirc;" },
+ { 245, "otilde;" },
+ { 246, "ouml;" },
+ { 248, "oslash;" },
+ { 339, "oelig;" },
+ { 959, "omicron;" },
+ { 969, "omega;" },
+ { 8254, "oline;" },
+ { 8744, "or;" },
+ { 8853, "oplus;" },
+ { 8855, "otimes;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_p[] = {
+ { 163, "pound;" },
+ { 177, "plusmn;" },
+ { 182, "para;" },
+ { 960, "pi;" },
+ { 966, "phi;" },
+ { 968, "psi;" },
+ { 982, "piv;" },
+ { 8240, "permil;" },
+ { 8242, "prime;" },
+ { 8706, "part;" },
+ { 8719, "prod;" },
+ { 8733, "prop;" },
+ { 8869, "perp;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_q[] = {
+ { 34, "quot;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_r[] = {
+ { 174, "reg;" },
+ { 187, "raquo;" },
+ { 961, "rho;" },
+ { 8207, "rlm;" },
+ { 8217, "rsquo;" },
+ { 8221, "rdquo;" },
+ { 8250, "rsaquo;" },
+ { 8476, "real;" },
+ { 8594, "rarr;" },
+ { 8658, "rArr;" },
+ { 8730, "radic;" },
+ { 8969, "rceil;" },
+ { 8971, "rfloor;" },
+ { 9002, "rang;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_s[] = {
+ { 167, "sect;" },
+ { 173, "shy;" },
+ { 178, "sup2;" },
+ { 179, "sup3;" },
+ { 185, "sup1;" },
+ { 223, "szlig;" },
+ { 353, "scaron;" },
+ { 962, "sigmaf;" },
+ { 963, "sigma;" },
+ { 8218, "sbquo;" },
+ { 8721, "sum;" },
+ { 8764, "sim;" },
+ { 8834, "sub;" },
+ { 8835, "sup;" },
+ { 8838, "sube;" },
+ { 8839, "supe;" },
+ { 8901, "sdot;" },
+ { 9824, "spades;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_t[] = {
+ { 215, "times;" },
+ { 254, "thorn;" },
+ { 732, "tilde;" },
+ { 952, "theta;" },
+ { 964, "tau;" },
+ { 977, "thetasym;" },
{ 8201, "thinsp;" },
+ { 8482, "trade;" },
+ { 8756, "there4;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_u[] = {
+ { 168, "uml;" },
+ { 249, "ugrave;" },
+ { 250, "uacute;" },
+ { 251, "ucirc;" },
+ { 252, "uuml;" },
+ { 965, "upsilon;" },
+ { 978, "upsih;" },
+ { 8593, "uarr;" },
+ { 8657, "uArr;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_w[] = {
+ { 8472, "weierp;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_x[] = {
+ { 958, "xi;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_y[] = {
+ { 165, "yen;" },
+ { 253, "yacute;" },
+ { 255, "yuml;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_z[] = {
+ { 950, "zeta;" },
{ 8203, "zwsp;" },
{ 8204, "zwnj;" },
{ 8205, "zwj;" },
- { 8206, "lrm;" },
- { 8207, "rlm;" },
- { 8211, "ndash;" },
- { 8212, "mdash;" },
- { 8216, "lsquo;" },
- { 8217, "rsquo;" },
- { 8218, "sbquo;" },
- { 8220, "ldquo;" },
- { 8221, "rdquo;" },
- { 8222, "bdquo;" },
- { 8224, "dagger;" },
- { 8225, "Dagger;" },
- { 8226, "bull;" },
- { 8230, "hellip;" },
- { 8240, "permil;" },
- { 8242, "prime;" },
- { 8243, "Prime;" },
- { 8249, "lsaquo;" },
- { 8250, "rsaquo;" },
- { 8254, "oline;" },
- { 8260, "frasl;" },
- { 8364, "euro;" },
- { 8465, "image;" },
- { 8472, "weierp;" },
- { 8476, "real;" },
- { 8482, "trade;" },
- { 8501, "alefsym;" },
- { 8592, "larr;" },
- { 8593, "uarr;" },
- { 8594, "rarr;" },
- { 8595, "darr;" },
- { 8596, "harr;" },
- { 8629, "crarr;" },
- { 8656, "lArr;" },
- { 8657, "uArr;" },
- { 8658, "rArr;" },
- { 8659, "dArr;" },
- { 8660, "hArr;" },
- { 8704, "forall;" },
- { 8706, "part;" },
- { 8707, "exist;" },
- { 8709, "empty;" },
- { 8711, "nabla;" },
- { 8712, "isin;" },
- { 8713, "notin;" },
- { 8715, "ni;" },
- { 8719, "prod;" },
- { 8721, "sum;" },
- { 8722, "minus;" },
- { 8727, "lowast;" },
- { 8730, "radic;" },
- { 8733, "prop;" },
- { 8734, "infin;" },
- { 8736, "ang;" },
- { 8743, "and;" },
- { 8744, "or;" },
- { 8745, "cap;" },
- { 8746, "cup;" },
- { 8747, "int;" },
- { 8756, "there4;" },
- { 8764, "sim;" },
- { 8773, "cong;" },
- { 8776, "asymp;" },
- { 8800, "ne;" },
- { 8801, "equiv;" },
- { 8804, "le;" },
- { 8805, "ge;" },
- { 8834, "sub;" },
- { 8835, "sup;" },
- { 8836, "nsub;" },
- { 8838, "sube;" },
- { 8839, "supe;" },
- { 8853, "oplus;" },
- { 8855, "otimes;" },
- { 8869, "perp;" },
- { 8901, "sdot;" },
- { 8968, "lceil;" },
- { 8969, "rceil;" },
- { 8970, "lfloor;" },
- { 8971, "rfloor;" },
- { 9001, "lang;" },
- { 9002, "rang;" },
- { 9674, "loz;" },
- { 9824, "spades;" },
- { 9827, "clubs;" },
- { 9829, "hearts;" },
- { 9830, "diams;" },
+ { 0, "" }
+};
- { 0, "" } // 終端
+static UCSTBL const ucstbl_A[] = {
+ { 192, "Agrave;" },
+ { 193, "Aacute;" },
+ { 194, "Acirc;" },
+ { 195, "Atilde;" },
+ { 196, "Auml;" },
+ { 197, "Aring;" },
+ { 198, "AElig;" },
+ { 913, "Alpha;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_B[] = {
+ { 914, "Beta;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_C[] = {
+ { 199, "Ccedil;" },
+ { 935, "Chi;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_D[] = {
+ { 916, "Delta;" },
+ { 8225, "Dagger;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_E[] = {
+ { 200, "Egrave;" },
+ { 201, "Eacute;" },
+ { 202, "Ecirc;" },
+ { 203, "Euml;" },
+ { 208, "ETH;" },
+ { 917, "Epsilon;" },
+ { 919, "Eta;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_G[] = {
+ { 915, "Gamma;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_I[] = {
+ { 204, "Igrave;" },
+ { 205, "Iacute;" },
+ { 206, "Icirc;" },
+ { 207, "Iuml;" },
+ { 921, "Iota;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_K[] = {
+ { 922, "Kappa;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_L[] = {
+ { 923, "Lambda;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_M[] = {
+ { 924, "Mu;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_N[] = {
+ { 209, "Ntilde;" },
+ { 925, "Nu;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_O[] = {
+ { 210, "Ograve;" },
+ { 211, "Oacute;" },
+ { 212, "Ocirc;" },
+ { 213, "Otilde;" },
+ { 214, "Ouml;" },
+ { 216, "Oslash;" },
+ { 338, "OElig;" },
+ { 927, "Omicron;" },
+ { 937, "Omega;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_P[] = {
+ { 928, "Pi;" },
+ { 934, "Phi;" },
+ { 936, "Psi;" },
+ { 8243, "Prime;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_R[] = {
+ { 929, "Rho;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_S[] = {
+ { 352, "Scaron;" },
+ { 931, "Sigma;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_T[] = {
+ { 222, "THORN;" },
+ { 920, "Theta;" },
+ { 932, "Tau;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_U[] = {
+ { 217, "Ugrave;" },
+ { 218, "Uacute;" },
+ { 219, "Ucirc;" },
+ { 220, "Uuml;" },
+ { 933, "Upsilon;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_X[] = {
+ { 926, "Xi;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_Y[] = {
+ { 221, "Yacute;" },
+ { 376, "Yuml;" },
+ { 0, "" }
+};
+
+static UCSTBL const ucstbl_Z[] = {
+ { 918, "Zeta;" },
+ { 0, "" }
+};
+
+static UCSTBL const * const ucstbl_small[] = {
+ ucstbl_a, ucstbl_b, ucstbl_c, ucstbl_d, ucstbl_e,
+ ucstbl_f, ucstbl_g, ucstbl_h, ucstbl_i, ucstbl_empty,
+ ucstbl_k, ucstbl_l, ucstbl_m, ucstbl_n, ucstbl_o,
+ ucstbl_p, ucstbl_q, ucstbl_r, ucstbl_s, ucstbl_t,
+ ucstbl_u, ucstbl_empty, ucstbl_w, ucstbl_x, ucstbl_y,
+ ucstbl_z
+};
+
+static UCSTBL const * const ucstbl_large[] = {
+ ucstbl_A, ucstbl_B, ucstbl_C, ucstbl_D, ucstbl_E,
+ ucstbl_empty, ucstbl_G, ucstbl_empty, ucstbl_I, ucstbl_empty,
+ ucstbl_K, ucstbl_L, ucstbl_M, ucstbl_N, ucstbl_O,
+ ucstbl_P, ucstbl_empty, ucstbl_R, ucstbl_S, ucstbl_T,
+ ucstbl_U, ucstbl_empty, ucstbl_empty, ucstbl_X, ucstbl_Y,
+ ucstbl_Z
};
enum
{
- UCS_ZWSP = 8203,
- UCS_ZWNJ = 8204,
- UCS_ZWJ = 8205,
- UCS_LRM = 8206,
- UCS_RLM = 8207,
+ UCS_HT = 9,
+ UCS_LF = 10,
+ UCS_FF = 12,
+ UCS_CR = 13,
+ UCS_SP = 32,
+ UCS_NBSP = 160,
+ UCS_ZWSP = 0x200B,
+ UCS_ZWNJ = 0x200C,
+ UCS_ZWJ = 0x200D,
+ UCS_LRM = 0x200E,
+ UCS_RLM = 0x200F,
+ UCS_LS = 0x2028,
+ UCS_PS = 0x2029,
+ UCS_REPLACE = 0xFFFD
};
+static unsigned short const charref_tbl [] = {
+ 0x20AC, // EURO SIGN (€)
+ 0x81, // U+0081 (HOP)
+ 0x201A, // SINGLE LOW-9 QUOTATION MARK (‚)
+ 0x0192, // LATIN SMALL LETTER F WITH HOOK (ƒ)
+ 0x201E, // DOUBLE LOW-9 QUOTATION MARK („)
+ 0x2026, // HORIZONTAL ELLIPSIS (…)
+ 0x2020, // DAGGER (†)
+ 0x2021, // DOUBLE DAGGER (‡)
+ 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ)
+ 0x2030, // PER MILLE SIGN (‰)
+ 0x0160, // LATIN CAPITAL LETTER S WITH CARON (Š)
+ 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹)
+ 0x0152, // LATIN CAPITAL LIGATURE OE (Œ)
+ 0x8D, // U+008D (RI)
+ 0x017D, // LATIN CAPITAL LETTER Z WITH CARON (Ž)
+ 0x8F, // U+008F (SS3)
+ 0x90, // U+0090 (DCS)
+ 0x2018, // LEFT SINGLE QUOTATION MARK (‘)
+ 0x2019, // RIGHT SINGLE QUOTATION MARK (’)
+ 0x201C, // LEFT DOUBLE QUOTATION MARK (“)
+ 0x201D, // RIGHT DOUBLE QUOTATION MARK (”)
+ 0x2022, // BULLET (•)
+ 0x2013, // EN DASH (–)
+ 0x2014, // EM DASH (—)
+ 0x02DC, // SMALL TILDE (˜)
+ 0x2122, // TRADE MARK SIGN (™)
+ 0x0161, // LATIN SMALL LETTER S WITH CARON (š)
+ 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›)
+ 0x0153, // LATIN SMALL LIGATURE OE (œ)
+ 0x9D, // U+009D (OSC)
+ 0x017E, // LATIN SMALL LETTER Z WITH CARON (ž)
+ 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ)
+};
+
#endif
diff --git a/src/dndmanager.h b/src/dndmanager.h
index ee58deee..414bb0de 100644
--- a/src/dndmanager.h
+++ b/src/dndmanager.h
@@ -27,7 +27,7 @@ namespace CORE
public:
DND_Manager():m_dnd( false ){}
- virtual ~DND_Manager() noexcept {}
+ virtual ~DND_Manager() noexcept = default;
bool now_dnd() const { return m_dnd; }
diff --git a/src/environment.cpp b/src/environment.cpp
index 2950e85d..1f05f0aa 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -1,8 +1,10 @@
// License GPL2
#ifdef _WIN32
+# ifndef WINVER
// require Windows XP SP2 or Server 2003 SP1 for GetNativeSystemInfo, KEY_WOW64_64KEY
-#define WINVER 0x0502
+# define WINVER 0x0502
+# endif
#endif
//#define _DEBUG
@@ -27,6 +29,14 @@
#include <windows.h>
#endif
+#if defined(USE_GNUTLS)
+# include <gnutls/gnutls.h>
+#elif defined(USE_OPENSSL)
+# include <openssl/ssl.h>
+#elif defined(USE_NSS)
+# include <nss/nss.h>
+#endif
+
std::string ENVIRONMENT::get_progname() { return "JDim"; }
std::string ENVIRONMENT::get_jdcomments(){ return std::string( JDCOMMENT ); }
std::string ENVIRONMENT::get_jdcopyright(){ return std::string( JDCOPYRIGHT ); }
@@ -311,12 +321,20 @@ std::string ENVIRONMENT::get_distname()
// OS architecture
if (osvi.dwMajorVersion >= 5)
{
- SYSTEM_INFO sysi;
- GetNativeSystemInfo(&sysi);
- if (sysi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
- vstr << " x64";
- else if (sysi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
- vstr << " ia64";
+ void (CALLBACK *pfn)(LPSYSTEM_INFO);
+
+ (*(FARPROC*)&pfn) = GetProcAddress( GetModuleHandle( "Kernel32.dll" ),
+ "GetNativeSystemInfo" );
+ if( pfn != NULL )
+ {
+ SYSTEM_INFO sysi;
+
+ pfn( &sysi );
+ if (sysi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ vstr << " x64";
+ else if (sysi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
+ vstr << " ia64";
+ }
}
break;
case VER_PLATFORM_WIN32_WINDOWS:
@@ -492,11 +510,12 @@ std::string ENVIRONMENT::get_distname()
( strlen( machine ) != 4
|| ! ( machine[0] == 'i'
&& machine[1] >= '3' && machine[1] <= '6'
- && machine[2] == '8' && machine[3] == '6' ) ) )
+ && machine[2] == '8' && machine[3] == '6' ) ) &&
+ dist_name.find( machine, 0 ) == std::string::npos )
{
- const std::string arch = "(" + std::string( machine ) + ")";
-
- if ( dist_name.find(arch, 0) == std::string::npos ) dist_name.append( " " + arch);
+ dist_name += " (";
+ dist_name += machine;
+ dist_name += ")";
}
free( uts );
@@ -509,22 +528,33 @@ std::string ENVIRONMENT::get_distname()
}
+static const char* const tbl_desktop[] = {
+ "GNOME", "XFCE", "KDE", "LXDE", "UNITY", "CINNAMON", "MATE",
+ "BUDGIE", "PANTHEON", "ENLIGHTENMENT", "(unknown)" };
+
//
// WM 判定
// TODO: 環境変数で判定できない場合の判定方法を考える
//
int ENVIRONMENT::get_wm()
{
+#ifndef _WIN32
if( window_manager != WM_UNKNOWN ) return window_manager;
- const std::string str_wm = MISC::getenv_limited( "DESKTOP_SESSION", 8 );
+ const char* const envver[] = { "DESKTOP_SESSION", "XDG_CURRENT_DESKTOP" };
- if( str_wm.find( "xfce" ) != std::string::npos ) window_manager = WM_XFCE;
- else if( str_wm.find( "gnome" ) != std::string::npos ) window_manager = WM_GNOME;
- else if( str_wm.find( "kde" ) != std::string::npos ) window_manager = WM_KDE;
- else if( str_wm.find( "LXDE" ) != std::string::npos ) window_manager = WM_LXDE;
- else if( str_wm.find( "mate" ) != std::string::npos ) window_manager = WM_MATE;
- else if( str_wm.find( "cinnamon" ) != std::string::npos ) window_manager = WM_CINNAMON;
+ for( size_t j=0; j<(sizeof envver/sizeof *envver); j++){
+
+ std::string str_wm = MISC::toupper_str( MISC::getenv_limited( envver[ j ], 20 ) );
+
+ if( !str_wm.empty() ){
+ for( int i = 0; i < WM_UNKNOWN; ++i ){
+ if( str_wm.find( tbl_desktop[ i ] ) != std::string::npos ){
+ window_manager = i;
+ }
+ }
+ }
+ }
if( window_manager == WM_UNKNOWN )
{
@@ -538,6 +568,7 @@ int ENVIRONMENT::get_wm()
if( str_wm == "true" ) window_manager = WM_KDE;
}
}
+#endif
return window_manager;
}
@@ -552,20 +583,12 @@ std::string ENVIRONMENT::get_wm_str()
#ifdef _WIN32
#ifdef __MINGW32__
- return std::string( "build by mingw32" );
+ desktop = "build by mingw32";
#else
- return std::string( "build with _WIN32" );
+ desktop = "build with _WIN32";
#endif
#else
- switch( get_wm() )
- {
- case WM_GNOME : desktop = "GNOME"; break;
- case WM_XFCE : desktop = "XFCE"; break;
- case WM_KDE : desktop = "KDE"; break;
- case WM_LXDE : desktop = "LXDE"; break;
- case WM_MATE : desktop = "MATE"; break;
- case WM_CINNAMON : desktop = "Cinnamon"; break;
- }
+ desktop = tbl_desktop[ get_wm() ];
#endif
return desktop;
@@ -600,6 +623,28 @@ std::string ENVIRONMENT::get_glibmm_version()
}
+//
+// TLSライブラリのバージョンを取得
+//
+std::string ENVIRONMENT::get_tlslib_version()
+{
+ std::string version;
+
+#if defined(USE_GNUTLS)
+ version = "GnuTLS ";
+ version +=gnutls_check_version(0);
+#elif defined(USE_OPENSSL)
+ version = SSLeay_version(SSLEAY_VERSION);
+#elif defined(USE_NSS)
+ version = "NSS ";
+ version += NSS_GetVersion();
+#endif
+
+ return version;
+}
+
+
+
//
// 動作環境を取得
//
@@ -635,7 +680,8 @@ std::string ENVIRONMENT::get_jdinfo()
"[パッケージ] " << "バイナリ/ソース( <配布元> )" << "\n" <<
"[ DE/WM ] " << desktop << "\n" <<
"[ gtkmm  ] " << get_gtkmm_version() << "\n" <<
- "[ glibmm  ] " << get_glibmm_version()<< "\n" <<
+ "[ glibmm  ] " << get_glibmm_version() << "\n" <<
+ "[ TLS lib ] " << get_tlslib_version() << "\n" <<
#ifdef CONFIGURE_ARGS
"[オプション ] " << get_configure_args( CONFIGURE_OMITTED_MULTILINE ) << "\n" <<
#endif
diff --git a/src/environment.h b/src/environment.h
index bbf8d038..179611c8 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -14,8 +14,12 @@ namespace ENVIRONMENT
WM_XFCE,
WM_KDE,
WM_LXDE,
- WM_MATE,
+ WM_UNITY,
WM_CINNAMON,
+ WM_MATE,
+ WM_BUDGIE,
+ WM_PANTHEON,
+ WM_ENLIGHTENMENT,
WM_UNKNOWN
};
@@ -43,6 +47,7 @@ namespace ENVIRONMENT
std::string get_wm_str();
std::string get_gtkmm_version();
std::string get_glibmm_version();
+ std::string get_tlslib_version();
std::string get_jdinfo();
}
diff --git a/src/fontcolorpref.cpp b/src/fontcolorpref.cpp
index a54469f3..8f9427f5 100644
--- a/src/fontcolorpref.cpp
+++ b/src/fontcolorpref.cpp
@@ -114,8 +114,7 @@ FontColorPref::FontColorPref( Gtk::Window* parent, const std::string& url )
}
-FontColorPref::~FontColorPref() noexcept
-{}
+FontColorPref::~FontColorPref() noexcept = default;
//
@@ -218,7 +217,7 @@ void FontColorPref::pack_widget()
m_liststore_color = Gtk::ListStore::create( m_columns_color );
m_treeview_color.set_model( m_liststore_color );
- m_treeview_color.set_size_request( 480, 280 );
+ m_treeview_color.set_size_request( 480, 250 );
m_treeview_color.get_selection()->set_mode( Gtk::SELECTION_MULTIPLE );
m_treeview_color.signal_row_activated().connect( sigc::mem_fun( *this, &FontColorPref::slot_row_activated ) );
m_scrollwin_color.add( m_treeview_color );
@@ -261,6 +260,10 @@ void FontColorPref::pack_widget()
m_chk_use_gtkrc_selection.set_active( CONFIG::get_use_select_gtkrc() );
m_vbox_color.pack_start( m_chk_use_gtkrc_selection, Gtk::PACK_SHRINK );
+ m_chk_use_html_color.add_label( "スレビューで HTML タグで指定された文字色を用いる(_H)", true ),
+ m_chk_use_html_color.set_active( CONFIG::get_use_color_html() );
+ m_vbox_color.pack_start( m_chk_use_html_color, Gtk::PACK_SHRINK );
+
m_bt_reset_all_colors.signal_clicked().connect( sigc::mem_fun( *this, &FontColorPref::slot_reset_all_colors ) );
m_vbox_color.pack_end( m_bt_reset_all_colors, Gtk::PACK_SHRINK );
@@ -293,12 +296,18 @@ void FontColorPref::slot_ok_clicked()
#endif
CONFIG::set_use_tree_gtkrc( m_chk_use_gtkrc_tree.property_active() );
CONFIG::set_use_select_gtkrc( m_chk_use_gtkrc_selection.property_active() );
+ std::string completely;
+ const bool use_color = m_chk_use_html_color.property_active();
+ if( use_color != CONFIG::get_use_color_html() ){
+ CONFIG::set_use_color_html( use_color );
+ completely = "completely";
+ }
CORE::core_set_command( "relayout_all_bbslist" );
CORE::core_set_command( "relayout_all_board" );
CORE::core_set_command( "init_font_all_article" );
- CORE::core_set_command( "relayout_all_article" );
+ CORE::core_set_command( "relayout_all_article", "", completely );
CORE::core_set_command( "relayout_all_message" );
}
@@ -573,6 +582,7 @@ void FontColorPref::slot_reset_all_colors()
#endif
m_chk_use_gtkrc_tree.set_active( CONFIG::CONF_USE_TREE_GTKRC );
m_chk_use_gtkrc_selection.set_active( CONFIG::CONF_USE_SELECT_GTKRC );
+ m_chk_use_html_color.set_active( CONFIG::CONF_USE_COLOR_HTML );
CONFIG::reset_colors();
diff --git a/src/fontcolorpref.h b/src/fontcolorpref.h
index 3e7acb19..15a42e25 100644
--- a/src/fontcolorpref.h
+++ b/src/fontcolorpref.h
@@ -75,6 +75,7 @@ namespace CORE
#endif
Gtk::CheckButton m_chk_use_gtkrc_tree;
Gtk::CheckButton m_chk_use_gtkrc_selection;
+ Gtk::CheckButton m_chk_use_html_color;
Gtk::TreeView m_treeview_color;
Glib::RefPtr< Gtk::ListStore > m_liststore_color;
diff --git a/src/global.h b/src/global.h
index 008f38b7..ded0836e 100644
--- a/src/global.h
+++ b/src/global.h
@@ -288,6 +288,7 @@ enum
#define URL_USRCMD "jdpref://usrcmd"
#define URL_LINKFILTER "jdpref://linkfilter"
+#define URL_REPLACESTR "jdpref://replacestr"
#define URL_BROWSER "jdpref://browser"
#define URL_ABOUTCONFIG "jdpref://aboutconfig"
#define URL_PRIVACY "jdpref://privacy"
diff --git a/src/globalabonepref.h b/src/globalabonepref.h
index bd1cb62d..332ecc13 100644
--- a/src/globalabonepref.h
+++ b/src/globalabonepref.h
@@ -76,7 +76,7 @@ namespace CORE
show_all_children();
}
- ~GlobalAbonePref() noexcept {}
+ ~GlobalAbonePref() noexcept = default;
};
}
diff --git a/src/globalabonethreadpref.h b/src/globalabonethreadpref.h
index 82f3dba6..b9ff5e4a 100644
--- a/src/globalabonethreadpref.h
+++ b/src/globalabonethreadpref.h
@@ -27,9 +27,13 @@ namespace CORE
Gtk::VBox m_vbox_abone_thread;
Gtk::Label m_label_abone_thread;
- Gtk::HBox m_hbox_number;
- Gtk::Label m_label_number;
- SKELETON::SpinButton m_spin_number;
+ Gtk::HBox m_hbox_min_number;
+ Gtk::Label m_label_min_number;
+ SKELETON::SpinButton m_spin_min_number;
+
+ Gtk::HBox m_hbox_max_number;
+ Gtk::Label m_label_max_number;
+ SKELETON::SpinButton m_spin_max_number;
Gtk::HBox m_hbox_hour;
Gtk::Label m_label_hour;
@@ -42,7 +46,8 @@ namespace CORE
// 全体あぼーん再設定
// スレ数、時間
- CONFIG::set_abone_number_thread( m_spin_number.get_value_as_int() );
+ CONFIG::set_abone_min_number_thread( m_spin_min_number.get_value_as_int() );
+ CONFIG::set_abone_max_number_thread( m_spin_max_number.get_value_as_int() );
CONFIG::set_abone_hour_thread( m_spin_hour.get_value_as_int() );
// word
@@ -69,16 +74,27 @@ namespace CORE
// スレ数、時間
m_label_abone_thread.set_text( "以下の数字が0の時は未設定になります。\nまたキャッシュにログがあるスレはあぼ〜んされません。\n\n" );
- m_label_number.set_text( "レス以上のスレをあぼ〜ん" );
- m_spin_number.set_range( 0, 9999 );
- m_spin_number.set_increments( 1, 1 );
- m_spin_number.set_value( CONFIG::get_abone_number_thread() );
-
- m_hbox_number.set_spacing( 4 );
- m_hbox_number.pack_start( m_spin_number, Gtk::PACK_SHRINK );
- m_hbox_number.pack_start( m_label_number, Gtk::PACK_SHRINK );
+ m_label_min_number.set_text( "レス以下のスレをあぼ〜ん" );
+ m_spin_min_number.set_range( 0, CONFIG::get_max_resnumber() );
+ m_spin_min_number.set_increments( 1, 1 );
+ m_spin_min_number.set_value( CONFIG::get_abone_min_number_thread() );
- set_activate_entry( m_spin_number );
+ m_hbox_min_number.set_spacing( 4 );
+ m_hbox_min_number.pack_start( m_spin_min_number, Gtk::PACK_SHRINK );
+ m_hbox_min_number.pack_start( m_label_min_number, Gtk::PACK_SHRINK );
+
+ set_activate_entry( m_spin_min_number );
+
+ m_label_max_number.set_text( "レス以上のスレをあぼ〜ん" );
+ m_spin_max_number.set_range( 0, CONFIG::get_max_resnumber() );
+ m_spin_max_number.set_increments( 1, 1 );
+ m_spin_max_number.set_value( CONFIG::get_abone_max_number_thread() );
+
+ m_hbox_max_number.set_spacing( 4 );
+ m_hbox_max_number.pack_start( m_spin_max_number, Gtk::PACK_SHRINK );
+ m_hbox_max_number.pack_start( m_label_max_number, Gtk::PACK_SHRINK );
+
+ set_activate_entry( m_spin_max_number );
m_label_hour.set_text( "時間以上スレ立てから経過したスレをあぼ〜ん" );
m_spin_hour.set_range( 0, 9999 );
@@ -94,7 +110,8 @@ namespace CORE
m_vbox_abone_thread.set_border_width( 16 );
m_vbox_abone_thread.set_spacing( 8 );
m_vbox_abone_thread.pack_start( m_label_abone_thread, Gtk::PACK_SHRINK );
- m_vbox_abone_thread.pack_start( m_hbox_number, Gtk::PACK_SHRINK );
+ m_vbox_abone_thread.pack_start( m_hbox_min_number, Gtk::PACK_SHRINK );
+ m_vbox_abone_thread.pack_start( m_hbox_max_number, Gtk::PACK_SHRINK );
m_vbox_abone_thread.pack_start( m_hbox_hour, Gtk::PACK_SHRINK );
// word
@@ -120,7 +137,7 @@ namespace CORE
show_all_children();
}
- ~GlobalAboneThreadPref() noexcept {}
+ ~GlobalAboneThreadPref() noexcept = default;
};
}
diff --git a/src/history/historymanager.cpp b/src/history/historymanager.cpp
index f71f99a1..e906bbbb 100644
--- a/src/history/historymanager.cpp
+++ b/src/history/historymanager.cpp
@@ -9,6 +9,7 @@
#include "viewhistoryitem.h"
#include "dbtree/interface.h"
+#include "jdlib/miscutil.h"
#include "xml/document.h"
#include "xml/tools.h"
@@ -146,7 +147,7 @@ void History_Manager::append_history( const std::string& url_history, const std:
if( url_history == URL_HISTTHREADVIEW || url_history == URL_HISTCLOSEVIEW ){
info.url = DBTREE::url_dat( url );
- info.name = DBTREE::article_subject( info.url );
+ info.name = MISC::to_plain( name );
}
if( url_history == URL_HISTBOARDVIEW || url_history == URL_HISTCLOSEBOARDVIEW ){
diff --git a/src/history/historymenu.cpp b/src/history/historymenu.cpp
index 8e8a8de9..496001a9 100644
--- a/src/history/historymenu.cpp
+++ b/src/history/historymenu.cpp
@@ -21,6 +21,9 @@ HistoryMenu::HistoryMenu( const std::string& url_history, const std::string& lab
}
+HistoryMenu::~HistoryMenu() noexcept = default;
+
+
void HistoryMenu::restore_history()
{
m_submenu->restore_history();
diff --git a/src/history/historymenu.h b/src/history/historymenu.h
index 37251ad4..fddcba80 100644
--- a/src/history/historymenu.h
+++ b/src/history/historymenu.h
@@ -21,6 +21,7 @@ namespace HISTORY
public:
HistoryMenu( const std::string& url_history, const std::string& label );
+ ~HistoryMenu() noexcept;
// 履歴の先頭を復元
void restore_history();
diff --git a/src/history/historysubmenu.cpp b/src/history/historysubmenu.cpp
index c04e62b1..310b7a3d 100644
--- a/src/history/historysubmenu.cpp
+++ b/src/history/historysubmenu.cpp
@@ -156,7 +156,7 @@ bool HistorySubMenu::open_history( const int i )
case TYPE_BOARD:
- CORE::core_set_command( "open_board" , DBTREE::url_subject( info_list[ i ].url ), tab, mode );
+ CORE::core_set_command( "open_board" , DBTREE::url_boardbase( info_list[ i ].url ), tab, mode );
ret = true;
break;
diff --git a/src/httpcode.h b/src/httpcode.h
index d3934ad6..ccc193d4 100644
--- a/src/httpcode.h
+++ b/src/httpcode.h
@@ -16,11 +16,15 @@ enum
HTTP_MOVED_PERM = 301,
HTTP_REDIRECT = 302,
HTTP_NOT_MODIFIED = 304,
+ HTTP_AUTH_REQ = 401,
HTTP_FORBIDDEN = 403,
HTTP_NOT_FOUND = 404,
HTTP_TIMEOUT = 408,
HTTP_RANGE_ERR = 416,
- HTTP_TEMP_UNAV = 503
+ HTTP_INTERNAL_SERVER_ERR = 500,
+ HTTP_NOT_IMPREMENTED = 501,
+ HTTP_TEMP_UNAV = 503,
+ HTTP_ORIGN_ERR = 520
};
#endif
diff --git a/src/icons/Makefile.am b/src/icons/Makefile.am
index bd1ee076..5f55b570 100644
--- a/src/icons/Makefile.am
+++ b/src/icons/Makefile.am
@@ -10,7 +10,7 @@ icon_headers = jd16.h jd32.h jd48.h jd96.h \
play.h hist.h hist_board.h hist_close.h hist_closeboard.h hist_closeimg.h info.h
noinst_HEADERS = \
- iconmanager.h iconid.h iconfiles.h $(icon_headers)
+ iconfiles.h iconid.h iconmanager.h $(icon_headers)
AM_CXXFLAGS = @GTKMM_CFLAGS@
AM_CPPFLAGS = -I$(top_srcdir)/src
diff --git a/src/image/imageview.cpp b/src/image/imageview.cpp
index 91b82ae9..161256b9 100644
--- a/src/image/imageview.cpp
+++ b/src/image/imageview.cpp
@@ -372,7 +372,12 @@ void ImageViewMain::show_status()
m_length_prev = get_img()->current_length();
char tmpstr[ 256 ];
- snprintf( tmpstr, 256, "%zd k / %zd k", m_length_prev/1024, get_img()->total_length()/1024 );
+#ifdef _WIN32
+ snprintf( tmpstr, sizeof( tmpstr ), "%u / %u KiB", m_length_prev/1024, get_img()->total_length()/1024 );
+#else
+ snprintf( tmpstr, sizeof( tmpstr ), "%zu / %zu KiB", m_length_prev/1024, get_img()->total_length()/1024 );
+#endif
+ tmpstr[ sizeof( tmpstr ) - 1 ] = '\0';
set_status_local( tmpstr );
add_tab_number();
diff --git a/src/image/imageviewpopup.cpp b/src/image/imageviewpopup.cpp
index c549fd92..25a93c6a 100644
--- a/src/image/imageviewpopup.cpp
+++ b/src/image/imageviewpopup.cpp
@@ -319,7 +319,12 @@ void ImageViewPopup::update_label()
m_length_prev = get_img()->current_length();
char tmpstr[ 256 ];
- snprintf( tmpstr, 256, "%zd k / %zd k", m_length_prev/1024, get_img()->total_length()/1024 );
+#if _WIN32
+ snprintf( tmpstr, sizeof( tmpstr ), "%u / %u KiB", m_length_prev/1024, get_img()->total_length()/1024 );
+#else
+ snprintf( tmpstr, sizeof( tmpstr ), "%zu / %zu KiB", m_length_prev/1024, get_img()->total_length()/1024 );
+#endif
+ tmpstr[ sizeof( tmpstr ) - 1 ] = '\0';
m_label->set_text( tmpstr );
}
}
diff --git a/src/image/preference.cpp b/src/image/preference.cpp
index eb1c5511..e4592cdb 100644
--- a/src/image/preference.cpp
+++ b/src/image/preference.cpp
@@ -33,7 +33,7 @@ Preferences::Preferences( Gtk::Window* parent, const std::string& url )
const std::string daturl = DBTREE::url_dat( refurl, num_from, num_to, num_str );
const std::string readcgi = DBTREE::url_readcgi( daturl, num_from, 0 );
- m_label_ref.set_text( DBTREE::article_subject( daturl ) );
+ m_label_ref.set_text( MISC::to_plain( DBTREE::article_modified_subject( daturl ) ) );
m_label_url_ref.set_text( readcgi );
m_open_ref.signal_clicked().connect( sigc::mem_fun(*this, &Preferences::slot_open_ref ) );
diff --git a/src/jdlib/Makefile.am b/src/jdlib/Makefile.am
index ef07047b..cd7a926f 100644
--- a/src/jdlib/Makefile.am
+++ b/src/jdlib/Makefile.am
@@ -13,7 +13,7 @@ libjdlib_a_SOURCES = \
jdiconv.cpp \
loader.cpp \
imgloader.cpp \
- ssl.cpp \
+ jdsocket.cpp \
loaderdata.cpp \
confloader.cpp \
jdregex.cpp \
@@ -36,7 +36,7 @@ noinst_HEADERS = \
jdiconv.h \
loader.h \
imgloader.h \
- ssl.h \
+ jdsocket.h \
loaderdata.h \
confloader.h \
jdregex.h \
@@ -45,5 +45,5 @@ noinst_HEADERS = \
timeout.h \
hkana.h
-AM_CXXFLAGS = @GTKMM_CFLAGS@ @GNUTLS_CFLAGS@ @OPENSSL_CFLAGS@ @X11_CFLAGS@
+AM_CXXFLAGS = @GTKMM_CFLAGS@ @GNUTLS_CFLAGS@ @OPENSSL_CFLAGS@ @NSS_CFLAGS@ @X11_CFLAGS@
AM_CPPFLAGS = -I$(top_srcdir)/src
diff --git a/src/jdlib/confloader.cpp b/src/jdlib/confloader.cpp
index 5dc04e1c..601be565 100644
--- a/src/jdlib/confloader.cpp
+++ b/src/jdlib/confloader.cpp
@@ -38,14 +38,12 @@ ConfLoader::ConfLoader( const std::string& file, std::string str_conf )
std::list < std::string >::iterator it = lines.begin();
for( ; it != lines.end(); ++it ){
- std::string line = MISC::remove_space( ( *it ) );
-
- size_t i = line.find( "=" );
+ size_t i = it->find_first_of( '=' );
if( i != std::string::npos ){
ConfData data;
- data.name = MISC::remove_space( line.substr( 0, i ) );
- data.value = MISC::remove_space( line.substr( i +1 ) );
+ data.name = MISC::remove_space( it->substr( 0, i ) );
+ data.value = MISC::remove_space( it->substr( i + 1 ) );
m_data.push_back( data );
#ifdef _DEBUG
std::cout << data.name << " = " << data.value << std::endl;
diff --git a/src/jdlib/confloader.h b/src/jdlib/confloader.h
index 4f35d9d4..ca172dd5 100644
--- a/src/jdlib/confloader.h
+++ b/src/jdlib/confloader.h
@@ -10,8 +10,6 @@
#include <string>
#include <list>
-#include "config/defaultconf.h"
-
namespace JDLIB
{
struct ConfData
diff --git a/src/jdlib/constptr.h b/src/jdlib/constptr.h
index 4bf145d0..f69ca173 100644
--- a/src/jdlib/constptr.h
+++ b/src/jdlib/constptr.h
@@ -16,7 +16,8 @@ namespace JDLIB
public:
- T* operator -> () const noexcept { return m_p; }
+ T* operator -> () noexcept { return m_p; }
+ const T* operator -> () const noexcept { return m_p; }
bool operator == ( const T *p ) const { return( m_p == p ); }
bool operator != ( const T *p ) const { return( m_p != p ); }
bool operator ! () const { return ( m_p == nullptr ); }
diff --git a/src/jdlib/heap.cpp b/src/jdlib/heap.cpp
index 3383931d..cb0452c7 100644
--- a/src/jdlib/heap.cpp
+++ b/src/jdlib/heap.cpp
@@ -59,13 +59,18 @@ unsigned char* HEAP::heap_alloc( long n )
m_used = 0;
#ifdef _DEBUG
- std::cout << "HEAP::heap_alloc malloc max = " << m_max << " total = " << m_total_size + n + 4 << std::endl;
+ std::cout << "HEAP::heap_alloc malloc max = " << m_max << " total = " << m_total_size + n << std::endl;
#endif
}
unsigned char* heap = m_heap_list.back() + m_used;
- m_used += n + 4;
- m_total_size += n + 4;
+#ifdef __i386__
+ if( n & 3 ) n = ( n + 4 ) & ~ 3;
+#else // __x86_64__ or etc
+ if( n & 7 ) n = ( n + 8 ) & ~ 7;
+#endif
+ m_used += n;
+ m_total_size += n;
return heap;
}
diff --git a/src/jdlib/imgloader.h b/src/jdlib/imgloader.h
index 9e7d8c94..2ef20aec 100644
--- a/src/jdlib/imgloader.h
+++ b/src/jdlib/imgloader.h
@@ -69,7 +69,7 @@ namespace JDLIB
std::mutex m_provider_lock; // ImgProvider操作時の必須ロック
public:
- virtual ~ImgProvider() noexcept {}
+ virtual ~ImgProvider() noexcept = default;
static ImgProvider& get_provider();
Glib::RefPtr< ImgLoader > get_loader( const std::string& file );
diff --git a/src/jdlib/jdiconv.cpp b/src/jdlib/jdiconv.cpp
index 81b540ee..d09a5711 100644
--- a/src/jdlib/jdiconv.cpp
+++ b/src/jdlib/jdiconv.cpp
@@ -5,9 +5,12 @@
#include "jddebug.h"
#include "jdiconv.h"
+#include "misccharcode.h"
#include "miscmsg.h"
#include "miscutil.h"
+#include "config/globalconf.h"
+
#include <errno.h>
#include <cstring>
#include <cstdio>
@@ -18,9 +21,9 @@ namespace
{
struct iconv_cast
{
- char** const m_t;
+ const char** const m_t;
iconv_cast() = delete;
- iconv_cast( char** t ) noexcept : m_t{ t } {}
+ iconv_cast( const char** t ) noexcept : m_t{ t } {}
~iconv_cast() noexcept = default;
// POSIX-1.2008 : https://pubs.opengroup.org/onlinepubs/9699919799/functions/iconv.html
@@ -33,42 +36,46 @@ struct iconv_cast
using namespace JDLIB;
-Iconv::Iconv( const std::string& coding_from, const std::string& coding_to )
- : m_buf_in( 0 ), m_buf_out( 0 ), m_coding_from( coding_from )
+Iconv::Iconv( const CharCode from, const CharCode to )
+ : m_cd( (iconv_t)-1 )
+ , m_buf_size( BUF_SIZE_ICONV_OUT )
+ , m_coding_from( from )
+ , m_coding_to( to )
{
#ifdef _DEBUG
- std::cout << "Iconv::Iconv coding = " << m_coding_from << " to " << coding_to << std::endl;
+ std::cout << "Iconv::Iconv coding = " << m_coding_from << " to " << m_coding_to << std::endl;
#endif
- m_buf_in = ( char* )malloc( BUF_SIZE_ICONV_IN );
- m_buf_out = ( char* )malloc( BUF_SIZE_ICONV_OUT );
+ m_buf = ( char* )malloc( m_buf_size );
+ const char* from_str = MISC::charcode_to_cstr( ( from == CHARCODE_UNKNOWN ) ? to : from );
+ const char* to_str = MISC::charcode_to_cstr( ( to == CHARCODE_UNKNOWN ) ? from : to );
- m_cd = iconv_open( coding_to.c_str(), m_coding_from.c_str() );
+ m_cd = iconv_open( to_str, from_str );
// MS932で失敗したらCP932で試してみる
if( m_cd == ( iconv_t ) -1 ){
- if( coding_to == "MS932" ) m_cd = iconv_open( "CP932", m_coding_from.c_str() );
- else if( coding_from == "MS932" ) m_cd = iconv_open( coding_to.c_str(), "CP932" );
+ if( to == CHARCODE_SJIS ) m_cd = iconv_open( "CP932", from_str );
+ else if( from == CHARCODE_SJIS ) m_cd = iconv_open( to_str, "CP932" );
}
// "EUCJP-*"で失敗したら"EUCJP"で試してみる
if( m_cd == ( iconv_t ) - 1 && ( errno & EINVAL ) != 0 )
{
- if( coding_to.find( "EUCJP-", 0 ) == 0 )
- {
- m_cd = iconv_open( "EUCJP//TRANSLIT", coding_from.c_str() );
- }
- else if( coding_from.find( "EUCJP-", 0 ) == 0 )
- {
- const std::string coding_to_translit = coding_to + "//TRANSLIT";
+ if( to == CHARCODE_EUCJP ) m_cd = iconv_open( "EUCJP//TRANSLIT", from_str );
+ else if( from == CHARCODE_EUCJP )
+ {
+ const std::string coding_to_translit = std::string( to_str ) + "//TRANSLIT";
m_cd = iconv_open( coding_to_translit.c_str(), "EUCJP" );
}
}
if( m_cd == ( iconv_t ) -1 ){
- MISC::ERRMSG( "can't open iconv coding = " + m_coding_from + " to " + coding_to );
+ std::string msg = "can't open iconv coding = ";
+ msg += MISC::charcode_to_cstr( from );
+ msg += " to ";
+ msg += MISC::charcode_to_cstr( to );
+ MISC::ERRMSG( msg );
}
- m_byte_left_in = 0;
}
Iconv::~Iconv()
@@ -77,48 +84,43 @@ Iconv::~Iconv()
std::cout << "Iconv::~Iconv\n";
#endif
- if( m_buf_in ) free( m_buf_in );
- if( m_buf_out ) free( m_buf_out );
+ if( m_buf ) free( m_buf );
if( m_cd != ( iconv_t ) -1 ) iconv_close( m_cd );
}
-const char* Iconv::convert( char* str_in, int size_in, int& size_out )
+const char* Iconv::convert( const char* str_in, int size_in, int& size_out )
{
#ifdef _DEBUG
- std::cout << "Iconv::convert size_in = " << size_in
- <<" left = " << m_byte_left_in << std::endl;
+ std::cout << "Iconv::convert size_in = " << size_in << std::endl;
#endif
- assert( m_byte_left_in + size_in < BUF_SIZE_ICONV_IN );
if( m_cd == ( iconv_t ) -1 ) return NULL;
- size_t byte_left_out = BUF_SIZE_ICONV_OUT;
- char* buf_out = m_buf_out;
+ const char* buf_in_tmp = str_in;
+ const char* buf_in_end = str_in + size_in;
- // 前回の残りをコピー
- if( m_byte_left_in ){
- memcpy( m_buf_in, m_buf_in_tmp, m_byte_left_in );
- m_buf_in_tmp = m_buf_in;
- memcpy( m_buf_in + m_byte_left_in , str_in, size_in );
- }
- else m_buf_in_tmp = str_in;
+ char* buf_out_tmp = m_buf;
+ char* buf_out_end = m_buf + m_buf_size;
- m_byte_left_in += size_in;
+ const char* pre_check = NULL; // 前回チェックしたUTF-8の先頭
// iconv 実行
do{
+ size_t byte_left_in = buf_in_end - buf_in_tmp;
+ size_t byte_left_out = buf_out_end - buf_out_tmp;
+
#ifdef _DEBUG
- std::cout << "m_byte_left_in = " << m_byte_left_in << std::endl;
+ std::cout << "byte_left_in = " << byte_left_in << std::endl;
std::cout << "byte_left_out = " << byte_left_out << std::endl;
#endif
- const int ret = iconv( m_cd, iconv_cast{ &m_buf_in_tmp }, &m_byte_left_in, &buf_out, &byte_left_out );
+ const int ret = iconv( m_cd, iconv_cast{ &buf_in_tmp }, &byte_left_in, &buf_out_tmp, &byte_left_out );
#ifdef _DEBUG
std::cout << "--> ret = " << ret << std::endl;
- std::cout << "m_byte_left_in = " << m_byte_left_in << std::endl;
+ std::cout << "byte_left_in = " << byte_left_in << std::endl;
std::cout << "byte_left_out = " << byte_left_out << std::endl;
#endif
@@ -130,66 +132,91 @@ const char* Iconv::convert( char* str_in, int size_in, int& size_out )
#ifdef _DEBUG_ICONV
char str_tmp[256];
#endif
- const unsigned char code0 = *m_buf_in_tmp;
- const unsigned char code1 = *(m_buf_in_tmp+1);
- const unsigned char code2 = *(m_buf_in_tmp+2);
-
- if( m_coding_from == "MS932" )
- {
-
- // 空白(0xa0)
- if( code0 == 0xa0 ){
- *m_buf_in_tmp = 0x20;
- continue;
- }
-
- // <>の誤判別 ( 開発スレ 489 を参照 )
- if( code1 == 0x3c && code2 == 0x3e ){
- *m_buf_in_tmp = '?';
+ const unsigned char code0 = *buf_in_tmp;
#ifdef _DEBUG_ICONV
- snprintf( str_tmp, 256, "iconv 0x%x%x> -> ?<>", code0, code1 );
- MISC::MSG( str_tmp );
+ const unsigned char code1 = *( buf_in_tmp + 1 );
+ const unsigned char code2 = *( buf_in_tmp + 2 );
#endif
- continue;
- }
- // マッピング失敗
- // □(0x81a0)を表示する
- if( ( code0 >= 0x81 && code0 <=0x9F )
- || ( code0 >= 0xe0 && code0 <=0xef ) ){
+ // MS932からUTF-8へマッピング失敗
+ if( m_coding_from == CHARCODE_SJIS && m_coding_to == CHARCODE_UTF8
+ && CONFIG::get_broken_sjis_be_utf8() ){
- *m_buf_in_tmp = static_cast< char >( 0x81 );
- *(m_buf_in_tmp+1) = static_cast< char >( 0xa0 );
+ // UTF-8へ変換する場合UTF-8の混在を許容する
+ const char* bpos = buf_in_tmp;
+ const char* epos = buf_in_tmp;
+ // マルチバイトUTF-8文字列の先頭と終端を調べる
+ while( bpos > str_in && *( bpos - 1 ) < 0 ) --bpos;
+ while( epos < ( buf_in_tmp + byte_left_in ) && *epos < 0 ) ++epos;
+
+ size_t lng = epos - bpos;
+
+ // 1byteは不正、また毎回同じ文字列を判定しない
+ if( lng > 1 && bpos != pre_check ){
+
+ // 一文字ずつUTF-8の文字か確認
+ size_t byte = 0;
+ pre_check = bpos;
+
+ if( MISC::is_utf8( bpos, lng, byte ) ){
#ifdef _DEBUG_ICONV
- snprintf( str_tmp, 256, "iconv 0x%x%x -> □ (0x81a0) ", code0, code1 );
- MISC::MSG( str_tmp );
+ std::string utf8( bpos, lng );
+ snprintf( str_tmp, 256, "iconv to be utf-8: %s", utf8.c_str() );
+ MISC::MSG( str_tmp );
#endif
- continue;
+
+ const char* const span_bgn = "<span class=\"BROKEN_SJIS\">";
+ const char* const span_end = "</span>";
+ const size_t lng_span_bgn = strlen( span_bgn );
+ const size_t lng_span_end = strlen( span_end );
+
+ while( buf_out_tmp > m_buf && *( buf_out_tmp - 1 ) < 0 ) --buf_out_tmp;
+ if( ( buf_out_tmp + lng + lng_span_bgn + lng_span_end ) >= buf_out_end ){
+ size_t used = buf_out_tmp - m_buf;
+ if( ! grow() ) break;
+ buf_out_tmp = m_buf + used;
+ buf_out_end = m_buf + m_buf_size;
+ }
+ memcpy( buf_out_tmp, span_bgn, lng_span_bgn );
+ buf_out_tmp += lng_span_bgn;
+ memcpy( buf_out_tmp, bpos, lng );
+ buf_out_tmp += lng;
+ memcpy( buf_out_tmp, span_end, lng_span_end );
+ buf_out_tmp += lng_span_end;
+ buf_in_tmp = bpos + lng;
+
+ continue;
+ }
}
}
// unicode 文字からの変換失敗
// 数値文字参照(&#????;)形式にする
- if( m_coding_from == "UTF-8" ){
+ if( m_coding_from == CHARCODE_UTF8 ){
int byte;
- const int ucs2 = MISC::utf8toucs2( m_buf_in_tmp, byte );
- if( byte != 1 ){
+ const int code = MISC::utf8tocp( buf_in_tmp, byte );
+ if( byte > 1 ){
- const std::string ucs2_str = MISC::itostr( ucs2 );
+ const std::string ucs_str = MISC::itostr( code );
#ifdef _DEBUG
- std::cout << "ucs2 = " << ucs2_str << " byte = " << byte << std::endl;
+ std::cout << "ucs = " << ucs_str << " byte = " << byte << std::endl;
#endif
- m_buf_in_tmp += byte;
- m_byte_left_in -= byte;
+ buf_in_tmp += byte;
- *(buf_out++) = '&';
- *(buf_out++) = '#';
- memcpy( buf_out, ucs2_str.c_str(), ucs2_str.size() ); buf_out += ucs2_str.size();
- *(buf_out++) = ';';
+ if( ( buf_out_tmp + ucs_str.length() + 3 ) >= buf_out_end ){
+ size_t used = buf_out_tmp - m_buf;
+ if( ! grow() ) break;
+ buf_out_tmp = m_buf + used;
+ buf_out_end = m_buf + m_buf_size;
+ }
- byte_left_out -= ucs2_str.size() + 3;
+ *(buf_out_tmp++) = '&';
+ *(buf_out_tmp++) = '#';
+ ucs_str.copy( buf_out_tmp, ucs_str.length() );
+ buf_out_tmp += ucs_str.length();
+ *(buf_out_tmp++) = ';';
continue;
}
@@ -198,12 +225,31 @@ const char* Iconv::convert( char* str_in, int size_in, int& size_out )
// 時々空白(0x20)で EILSEQ が出るときがあるのでもう一度トライする
if( code0 == 0x20 ) continue;
- //その他、1文字を空白にして続行
#ifdef _DEBUG_ICONV
- snprintf( str_tmp, 256, "iconv EILSEQ left = %zd code = %x %x %x", m_byte_left_in, code0, code1, code2 );
+ snprintf( str_tmp, 256, "iconv EILSEQ left = %zd code = %x %x %x", byte_left_in, code0, code1, code2 );
MISC::ERRMSG( str_tmp );
#endif
- *m_buf_in_tmp = 0x20;
+
+ // BOFの確認
+ if( ( buf_out_end - buf_out_tmp ) <= 3 ){
+ size_t used = buf_out_tmp - m_buf;
+ if( ! grow() ) break;
+ buf_out_tmp = m_buf + used;
+ buf_out_end = m_buf + m_buf_size;
+ }
+
+ // UTF-8へ変換する場合はREPLACEMENT CHARACTERに置き換える
+ if( m_coding_to == CHARCODE_UTF8 ){
+ ++buf_in_tmp;
+ *(buf_out_tmp++) = static_cast< char >( 0xef );
+ *(buf_out_tmp++) = static_cast< char >( 0xbf );
+ *(buf_out_tmp++) = static_cast< char >( 0xbd );
+ continue;
+ }
+
+ //その他、1文字を?にして続行
+ ++buf_in_tmp;
+ *(buf_out_tmp++) = '?';
}
else if( errno == EINVAL ){
@@ -217,14 +263,32 @@ const char* Iconv::convert( char* str_in, int size_in, int& size_out )
#ifdef _DEBUG_ICONV
MISC::ERRMSG( "iconv E2BIG\n" );
#endif
- break;
+ size_t used = buf_out_tmp - m_buf;
+ if( ! grow() ) break;
+ buf_out_tmp = m_buf + used;
+ buf_out_end = m_buf + m_buf_size;
+ continue;
}
}
- } while( m_byte_left_in > 0 );
+ } while( buf_in_tmp < buf_in_end );
- size_out = BUF_SIZE_ICONV_OUT - byte_left_out;
- m_buf_out[ size_out ] = '\0';
+ size_out = buf_out_tmp - m_buf;
+ *buf_out_tmp = '\0';
- return m_buf_out;
+#ifdef _DEBUG
+ std::cout << "Iconv::convert size_out = " << size_out << std::endl;
+#endif
+ return m_buf;
+}
+
+
+
+bool Iconv::grow()
+{
+ m_buf_size += BUF_SIZE_ICONV_OUT;
+ char *tmp = ( char* )realloc( m_buf, m_buf_size );
+ if( ! tmp ) return false;
+ m_buf = tmp;
+ return true;
}
diff --git a/src/jdlib/jdiconv.h b/src/jdlib/jdiconv.h
index f50e5427..c274f4fb 100644
--- a/src/jdlib/jdiconv.h
+++ b/src/jdlib/jdiconv.h
@@ -3,15 +3,14 @@
#ifndef _JDICONV_H
#define _JDICONV_H
+#include "charcode.h"
+
#include <iconv.h>
#include <string>
-// iconv の内部で確保するバッファサイズ(バイト)
-// BUF_SIZE_ICONV_IN を超える入力は扱えないので注意
enum
{
- BUF_SIZE_ICONV_IN = 1024 * 1024,
- BUF_SIZE_ICONV_OUT = BUF_SIZE_ICONV_IN /2 * 3
+ BUF_SIZE_ICONV_OUT = 512 * 1024,
};
namespace JDLIB
@@ -20,20 +19,21 @@ namespace JDLIB
{
iconv_t m_cd;
- size_t m_byte_left_in;
- char* m_buf_in;
- char* m_buf_in_tmp;
+ char* m_buf;
+ size_t m_buf_size;
- char* m_buf_out;
-
- std::string m_coding_from;
+ CharCode m_coding_from;
+ CharCode m_coding_to;
public:
- Iconv( const std::string& coding_from, const std::string& coding_to );
+ Iconv( const CharCode from, const CharCode to );
~Iconv();
- const char* convert( char* str_in, int size_in, int& size_out );
+ const char* convert( const char* str_in, int size_in, int& size_out );
+
+ private:
+ bool grow();
};
}
diff --git a/src/jdlib/jdmigemo.cpp b/src/jdlib/jdmigemo.cpp
index 4555a395..d3d70402 100644
--- a/src/jdlib/jdmigemo.cpp
+++ b/src/jdlib/jdmigemo.cpp
@@ -24,20 +24,20 @@
migemo *migemo_object;
-int jd_migemo_regcomp(regex_t *preg,const char *regex,int cflags)
+char* jd_migemo_regcreate(const char *regex,int cflags)
{
migemo *m;
- int retval,i;
+ int i;
size_t len;
unsigned char *p,*utmp;
char *ctmp;
m=migemo_object;
if(!m){
- return -1;
+ return NULL;
}
//migemo_load(m,MIGEMO_DICTID_MIGEMO,JD_MIGEMO_DICTNAME);
if(!migemo_is_enable(m)){
- return -1;
+ return NULL;
}
utmp=(unsigned char *)calloc(sizeof(unsigned char),strlen(regex)+1);
memcpy(utmp,regex,strlen(regex));
@@ -49,21 +49,16 @@ int jd_migemo_regcomp(regex_t *preg,const char *regex,int cflags)
}
p=migemo_query(m,utmp);
free(utmp);
- for(len=0;p[len]!='\0';len++);
- ctmp=(char *)calloc(sizeof(char),len+1);
+ len=strlen((char*)p)+1;
+ ctmp=(char *)malloc(len);
memcpy(ctmp,p,len);
#ifdef _DEBUG
std::cout << "migemo comp:" << ctmp << std::endl;
#endif
- retval=regcomp(preg,ctmp,cflags);
- free(ctmp);
- if(retval!=0){
- regfree(preg);
- }
migemo_release(m,p);
- return retval;
+ return ctmp;
}
diff --git a/src/jdlib/jdmigemo.h b/src/jdlib/jdmigemo.h
index 33798543..1cdf27d8 100644
--- a/src/jdlib/jdmigemo.h
+++ b/src/jdlib/jdmigemo.h
@@ -12,13 +12,12 @@
#ifdef HAVE_MIGEMO_H
#include <migemo.h>
-#include "jdregex.h"
#ifdef __cplusplus
extern "C" {
#endif
- int jd_migemo_regcomp(regex_t *preg,const char *regex,int cflags);
+ char* jd_migemo_regcreate(const char *regex,int cflags);
int jd_migemo_init(const char *filename);
int jd_migemo_close(void);
diff --git a/src/jdlib/jdregex.cpp b/src/jdlib/jdregex.cpp
index 760ea48d..4da2c558 100644
--- a/src/jdlib/jdregex.cpp
+++ b/src/jdlib/jdregex.cpp
@@ -20,47 +20,69 @@ enum
using namespace JDLIB;
-Regex::Regex()
- : m_compiled(false)
+
+RegexPattern::RegexPattern( const std::string& reg, const bool icase, const bool newline,
+ const bool usemigemo, const bool wchar, const bool norm )
+ : m_compiled( false )
+ , m_error( 0 )
{
- m_results.clear();
- m_pos.clear();
+ set( reg, icase, newline, usemigemo, wchar, norm );
}
-Regex::~Regex()
+RegexPattern::~RegexPattern()
{
- dispose();
+ clear();
}
-
-void Regex::dispose()
+void RegexPattern::clear()
{
- if ( m_compiled ) {
- regfree( &m_reg );
- m_compiled = false;
- }
-}
+ if( m_compiled )
+#if USE_REGEX_COMPAT
+ regfree( &m_regex );
+#else
+ g_regex_unref( m_regex );
+#endif
+ m_compiled = false;
+#if USE_REGEX_COMPAT
+ m_error = 0;
+#else
+ g_clear_error( &m_error );
+#endif
+}
// icase : 大文字小文字区別しない
// newline : . に改行をマッチさせない
// usemigemo : migemo使用 (コンパイルオプションで指定する必要あり)
// wchar : 全角半角の区別をしない
-bool Regex::compile( const std::string reg, const bool icase, const bool newline, const bool use_migemo, const bool wchar )
+bool RegexPattern::set( const std::string& reg, const bool icase, const bool newline,
+ const bool usemigemo, const bool wchar, const bool norm )
{
#ifdef _DEBUG
if( wchar ){
- std::cout << "Regex::compile\n";
- std::cout << reg << std::endl;
+ std::cout << "RegexPattern::set " << reg << std::endl;
}
#endif
- dispose();
+ if( m_compiled ){
+#if USE_REGEX_COMPAT
+ regfree( &m_regex );
+#else
+ g_regex_unref( m_regex );
+#endif
+ m_compiled = false;
+ }
+#if USE_REGEX_COMPAT
+ m_error = 0;
+#else
+ g_clear_error( &m_error );
+#endif
if( reg.empty() ) return false;
-#ifdef USE_PCRE
+#if USE_REGEX_COMPAT
+#ifdef HAVE_PCREPOSIX_H
int cflags = REG_UTF8;
if( ! newline ) cflags |= REG_DOTALL; // . を改行にマッチさせる
#else
@@ -68,14 +90,153 @@ bool Regex::compile( const std::string reg, const bool icase, const bool newline
#endif
if( newline ) cflags |= REG_NEWLINE;
if( icase ) cflags |= REG_ICASE;
+#else
+ int cflags = G_REGEX_OPTIMIZE;
+ if( newline ) cflags |= G_REGEX_MULTILINE;
+ else cflags |= G_REGEX_DOTALL; // . を改行にマッチさせる
+ if( icase ) cflags |= G_REGEX_CASELESS;
+#endif //USE_REGEX_COMPAT
m_newline = newline;
m_wchar = wchar;
+ m_norm = norm;
const char* asc_reg = reg.c_str();
+ std::string target_asc;
+
+ // Unicode正規化
+ if( m_norm ){
+ target_asc.reserve( MAX_TARGET_SIZE );
+ std::vector<int> temp;
+ MISC::norm( asc_reg, target_asc, temp );
+ asc_reg = target_asc.c_str();
+
+#ifdef _DEBUG
+ std::cout << target_asc << std::endl;
+#endif
+ }
// 全角英数字 → 半角英数字、半角カナ → 全角カナ
- if( m_wchar && MISC::has_widechar( asc_reg ) ){
+ else if( m_wchar && MISC::has_widechar( asc_reg ) ){
+
+ target_asc.reserve( MAX_TARGET_SIZE );
+ std::vector<int> temp;
+ MISC::asc( asc_reg, target_asc, temp );
+ asc_reg = target_asc.c_str();
+
+#ifdef _DEBUG
+ std::cout << target_asc << std::endl;
+#endif
+ }
+
+#ifdef HAVE_MIGEMO_H
+
+ if( usemigemo ){
+ char *mgm_reg = jd_migemo_regcreate( asc_reg, cflags );
+ if( mgm_reg != NULL ){
+#if USE_REGEX_COMPAT
+ m_error = regcomp( &m_regex, mgm_reg, cflags );
+ free( mgm_reg );
+ if( m_error != 0 ) regfree( &m_regex );
+#else
+ m_regex = g_regex_new( mgm_reg, GRegexCompileFlags( cflags ), GRegexMatchFlags( 0 ), &m_error );
+ free( mgm_reg );
+ if( m_regex == NULL ) g_clear_error( &m_error );
+#endif
+ else goto compile_done;
+ }
+ }
+#endif //HAVE_MIGEMO_H
+
+#if USE_REGEX_COMPAT
+ m_error = regcomp( &m_regex, asc_reg, cflags );
+ if( m_error != 0 ){
+ regfree( &m_regex );
+ return false;
+ }
+#else
+ m_regex = g_regex_new( asc_reg, GRegexCompileFlags( cflags ), GRegexMatchFlags( 0 ), &m_error );
+ if( m_regex == NULL ){
+ return false;
+ }
+#endif
+
+#ifdef HAVE_MIGEMO_H
+compile_done:
+#endif
+
+ m_compiled = true;
+ return true;
+}
+
+
+std::string RegexPattern::errstr() const
+{
+ std::string errmsg;
+
+#if USE_REGEX_COMPAT
+ switch( m_error ){
+ case 0: errmsg = "エラーはありません。"; break;
+ case REG_BADBR: errmsg = "無効な後方参照オペレータを使用しています。"; break;
+ case REG_BADPAT: errmsg = "無効なグループやリストなどを使用しています。"; break;
+ case REG_BADRPT: errmsg = "'*' が最初の文字としてくるような、無効な繰り返しオペレータを使用しています。"; break;
+ case REG_EBRACE: errmsg = "インターバルオペレータ {} が閉じていません。"; break;
+ case REG_EBRACK: errmsg = "リストオペレータ [] が閉じていません。"; break;
+ case REG_ECOLLATE: errmsg = "照合順序の要素として有効ではありません。"; break;
+ case REG_ECTYPE: errmsg = "未知のキャラクタークラス名です。"; break;
+#ifdef HAVE_REGEX_H
+ case REG_EEND: errmsg = "未定義エラー。POSIX.2 には定義されていません。"; break;
+#endif
+ case REG_EESCAPE: errmsg = "正規表現がバックスラッシュで終っています。"; break;
+ case REG_EPAREN: errmsg = "グループオペレータ () が閉じていません。"; break;
+ case REG_ERANGE: errmsg = "無効な範囲オペレータを使用しています。"; break;
+#ifndef HAVE_ONIGPOSIX_H
+ case REG_ESIZE: errmsg = "複雑過ぎる正規表現です。POSIX.2 には定義されていません。"; break;
+#endif
+ case REG_ESPACE: errmsg = "regex ルーチンがメモリーを使い果たしました。"; break;
+ case REG_ESUBREG: errmsg = "サブエクスプレッション (...) への無効な後方参照です。"; break;
+ default: errmsg = "未知のエラーが発生しました。"; break;
+ }
+#else
+ errmsg = m_error->message;
+#endif
+ return errmsg;
+}
+
+
+///////////////////////////////////////////////
+
+Regex::Regex() noexcept
+{
+ m_results.clear();
+ m_pos.clear();
+}
+
+
+Regex::~Regex() noexcept = default;
+
+
+bool Regex::match( const RegexPattern& creg, const std::string& target, const size_t offset, const bool notbol, const bool noteol )
+{
+ m_pos.clear();
+ m_results.clear();
+
+ if ( ! creg.m_compiled ) return false;
+
+ if( target.empty() ) return false;
+ if( target.length() <= offset ) return false;
+
+ const char* asc_target = target.c_str() + offset;
+
+ bool exec_asc = false;
+
+ // Unicode正規化
+ if( creg.m_norm ){
+
+#ifdef _DEBUG
+ std::cout << "Regex::match offset = " << offset << std::endl;
+ std::cout << target << std::endl;
+#endif
m_target_asc.clear();
m_table_pos.clear();
@@ -84,66 +245,20 @@ bool Regex::compile( const std::string reg, const bool icase, const bool newline
m_table_pos.reserve( MAX_TARGET_SIZE );
}
- MISC::asc( asc_reg, m_target_asc, m_table_pos );
- asc_reg = m_target_asc.c_str();
+ MISC::norm( asc_target, m_target_asc, m_table_pos );
+ exec_asc = true;
+ asc_target = m_target_asc.c_str();
#ifdef _DEBUG
std::cout << m_target_asc << std::endl;
#endif
}
-#ifdef HAVE_MIGEMO_H
-
- if( use_migemo ){
-
- if( jd_migemo_regcomp( &m_reg, asc_reg, cflags ) != 0 ){
-
- if( regcomp( &m_reg, asc_reg, cflags ) != 0 ){
- regfree( &m_reg );
- return false;
- }
- }
- }
- else{
-#endif
-
- if( regcomp( &m_reg, asc_reg, cflags ) != 0 ){
- regfree( &m_reg );
- return false;
- }
-
-#ifdef HAVE_MIGEMO_H
- }
-#endif
-
- m_compiled = true;
- return true;
-}
-
-
-bool Regex::exec( const std::string& target, const size_t offset )
-{
- regmatch_t pmatch[ REGEX_MAX_NMATCH ];
-
- memset(pmatch, 0, sizeof(pmatch));
-
- if ( ! m_compiled ) return false;
-
- if( target.empty() ) return false;
- if( target.length() <= offset ) return false;
-
- m_pos.clear();
- m_results.clear();
-
- const char* asc_target = target.c_str() + offset;
-
- bool exec_asc = false;
-
// 全角英数字 → 半角英数字、半角カナ → 全角カナ
- if( m_wchar && MISC::has_widechar( asc_target ) ){
+ else if( creg.m_wchar && MISC::has_widechar( asc_target ) ){
#ifdef _DEBUG
- std::cout << "Regex::exec offset = " << offset << std::endl;
+ std::cout << "Regex::match offset = " << offset << std::endl;
std::cout << target << std::endl;
#endif
@@ -163,15 +278,30 @@ bool Regex::exec( const std::string& target, const size_t offset )
#endif
}
-#ifdef USE_ONIG
+#if USE_REGEX_COMPAT
+ regmatch_t pmatch[ REGEX_MAX_NMATCH ];
+ memset( pmatch, 0, sizeof( pmatch ));
+
+ int eflags = 0;
+ if( notbol ) eflags |= REG_NOTBOL;
+ if( noteol ) eflags |= REG_NOTEOL;
+#else
+ GMatchInfo *pmatch;
+
+ int eflags = 0;
+ if( notbol ) eflags |= G_REGEX_MATCH_NOTBOL;
+ if( noteol ) eflags |= G_REGEX_MATCH_NOTEOL;
+#endif
+
+#ifdef HAVE_ONIGPOSIX_H
// 鬼車はnewlineを無視するようなので、文字列のコピーを取って
// 改行をスペースにしてから実行する
- if( ! m_newline ){
+ if( ! creg.m_newline ){
std::string target_copy = asc_target;
for( size_t i = 0; i < target_copy.size(); ++i ) if( target_copy[ i ] == '\n' ) target_copy[ i ] = ' ';
- if( regexec( &m_reg, target_copy.c_str(), REGEX_MAX_NMATCH, pmatch, 0 ) != 0 ){
+ if( regexec( &creg.m_regex, target_copy.c_str(), REGEX_MAX_NMATCH, pmatch, eflags ) != 0 ){
return false;
}
}
@@ -179,58 +309,93 @@ bool Regex::exec( const std::string& target, const size_t offset )
#endif
- if( regexec( &m_reg, asc_target, REGEX_MAX_NMATCH, pmatch, 0 ) != 0 ){
+#if USE_REGEX_COMPAT
+ if( regexec( &creg.m_regex, asc_target, REGEX_MAX_NMATCH, pmatch, eflags ) != 0 ){
return false;
}
-
- for( int i = 0; i < REGEX_MAX_NMATCH; ++i ){
-
- int so = pmatch[ i ].rm_so;
- int eo = pmatch[ i ].rm_eo;
- if( exec_asc && so >= 0 && eo >= 0 ){
-#ifdef _DEBUG
- std::cout << "so = " << so << " eo = " << eo;
+ const int match_count = REGEX_MAX_NMATCH;
+#else
+ if( ! g_regex_match( creg.m_regex, asc_target, GRegexMatchFlags( eflags ), &pmatch ) ){
+ g_match_info_free( pmatch );
+ return false;
+ }
+ const int match_count = g_match_info_get_match_count( pmatch ) + 1;
#endif
- so = m_table_pos[ so ];
- eo = m_table_pos[ eo ];
-#ifdef _DEBUG
- std::cout << " -> so = " << so << " eo = " << eo << std::endl;
+
+ for( int i = 0; i < match_count; ++i ){
+
+ int so, eo;
+#if USE_REGEX_COMPAT
+ so = pmatch[ i ].rm_so;
+ eo = pmatch[ i ].rm_eo;
+#else
+ if( ! g_match_info_fetch_pos( pmatch, i, &so, &eo ) ) so = eo = -1;
#endif
+
+ if( so < 0 || eo < 0 ){
+ m_pos.push_back( so );
+ m_results.push_back( std::string() );
}
- so += offset;
- eo += offset;
- m_pos.push_back( so );
+ else{
+ if( exec_asc ){
+#ifdef _DEBUG
+ std::cout << "so=" << so << " eo=" << eo;
+#endif
+ while( so > 0 && m_table_pos[ so ] < 0 ) so--;
+ so = m_table_pos[ so ];
+ while( m_table_pos[ eo ] < 0 ) eo++;
+ eo = m_table_pos[ eo ];
+#ifdef _DEBUG
+ std::cout << " -> so=" << so << " eo=" << eo << std::endl;
+#endif
+ }
+ so += offset;
+ eo += offset;
- if( so >= 0 && eo >= 0 ) m_results.push_back( target.substr( so, eo - so ) );
- else m_results.push_back( std::string() );
+ m_pos.push_back( so );
+ m_results.push_back( target.substr( so, eo - so ) );
+ }
}
+#if !USE_REGEX_COMPAT
+ g_match_info_free( pmatch );
+#endif
+
return true;
}
-// icase : 大文字小文字区別しない
-// newline : . に改行をマッチさせない
-// usemigemo : migemo使用 (コンパイルオプションで指定する必要あり)
-// wchar : 全角半角の区別をしない
-bool Regex::exec( const std::string reg, const std::string& target,
- const size_t offset, const bool icase, const bool newline, const bool use_migemo, const bool wchar )
+//
+// マッチした文字列と $0〜$9 or \0〜\9 を置換する
+//
+std::string Regex::replace( const std::string& repstr )
{
- if ( ! compile(reg, icase, newline, use_migemo, wchar ) ) return false;
+ if( repstr.empty() ) return repstr;
- if ( ! exec(target, offset) ){
- dispose();
- return false;
+ const char* p0 = repstr.c_str();
+ const char* p1;
+ std::string str_out;
+
+ while( ( p1 = strchr( p0, '\\' ) ) != NULL ){
+ int n = p1[ 1 ] - '0';
+ str_out.append( p0, p1 - p0 );
+ p0 = p1 + 2;
+ if( n < 0 || n > 9 ){
+ str_out.push_back( p1[ 1 ] );
+ }
+ else if( m_results.size() > ( size_t )n && m_pos[ n ] != -1 ){
+ str_out += m_results[ n ];
+ }
}
- dispose();
+ str_out.append( repstr, p0 - repstr.c_str(), std::string::npos );
- return true;
+ return str_out;
}
-std::string Regex::str( const size_t num )
+std::string Regex::str( const size_t num ) const
{
if( m_results.size() > num ) return m_results[ num ];
@@ -238,7 +403,7 @@ std::string Regex::str( const size_t num )
}
-int Regex::pos( const size_t num )
+int Regex::pos( const size_t num ) const
{
if( m_results.size() > num ) return m_pos[ num ];
diff --git a/src/jdlib/jdregex.h b/src/jdlib/jdregex.h
index a192bb56..81d48f2e 100644
--- a/src/jdlib/jdregex.h
+++ b/src/jdlib/jdregex.h
@@ -10,25 +10,74 @@
#include "config.h"
#endif
-#ifdef USE_ONIG
+#ifdef HAVE_ONIGPOSIX_H
#include <onigposix.h>
-#elif defined( USE_PCRE )
+#elif defined( HAVE_PCREPOSIX_H )
#include <pcreposix.h>
-#else
+#elif defined( HAVE_REGEX_H )
#include <regex.h>
+#else
+#include <glib.h>
#endif /** USE_ONIG **/
+#if defined( HAVE_ONIGPOSIX_H ) || defined( HAVE_PCREPOSIX_H ) || defined( HAVE_REGEX_H )
+#define USE_REGEX_COMPAT 1
+#else
+#define USE_REGEX_COMPAT 0
+#endif
namespace JDLIB
{
+ class Regex;
+
+ class RegexPattern
+ {
+ friend class Regex;
+
+#if USE_REGEX_COMPAT
+ // onigurumaではregexec()の引数regex_t*がconst修飾されていない
+ // そのためRegex::match()のコンパイルエラーを回避するためmutable修飾が必要
+ mutable regex_t m_regex;
+#else
+ GRegex *m_regex;
+#endif
+ bool m_compiled;
+ bool m_newline;
+ bool m_wchar;
+ bool m_norm;
+#if USE_REGEX_COMPAT
+ int m_error;
+#else
+ GError *m_error;
+#endif
+
+ public:
+ RegexPattern() : m_compiled( false ), m_error( 0 ){};
+ RegexPattern( const std::string& reg, const bool icase, const bool newline,
+ const bool usemigemo = false, const bool wchar = false,
+ const bool norm = false );
+ ~RegexPattern();
+
+ // m_regexを複製する方法がないためcopy禁止にする
+ RegexPattern( const RegexPattern& ) = delete;
+ RegexPattern& operator=( const RegexPattern& ) = delete;
+ // moveは許可
+ RegexPattern( RegexPattern&& ) noexcept = default;
+ RegexPattern& operator=( RegexPattern&& ) noexcept = default;
+
+ bool set( const std::string& reg, const bool icase, const bool newline,
+ const bool usemigemo = false, const bool wchar = false,
+ const bool norm = false );
+ void clear();
+ bool compiled() const { return m_compiled; }
+ std::string errstr() const;
+ };
+
+
class Regex
{
std::vector< int > m_pos;
std::vector< std::string > m_results;
- regex_t m_reg;
- bool m_compiled;
- bool m_newline;
- bool m_wchar;
// 全角半角を区別しないときに使う変換用バッファ
// 処理可能なバッファ長は regoff_t (= int) のサイズに制限される
@@ -37,24 +86,30 @@ namespace JDLIB
public:
- Regex();
- ~Regex();
+ Regex() noexcept;
+ ~Regex() noexcept;
- void dispose();
+ // notbol : 行頭マッチは必ず失敗する
+ // noteol : 行末マッチは必ず失敗する
+ bool match( const RegexPattern& creg, const std::string& target, const size_t offset,
+ const bool notbol = false, const bool noteol = false );
// icase : 大文字小文字区別しない
// newline : . に改行をマッチさせない
// usemigemo : migemo使用 (コンパイルオプションで指定する必要あり)
// wchar : 全角半角の区別をしない
- bool compile( const std::string reg, const bool icase, const bool newline, const bool usemigemo,
- const bool wchar );
+ bool exec( const std::string& reg, const std::string& target, const size_t offset,
+ const bool icase, const bool newline, const bool usemigemo = false,
+ const bool wchar = false, const bool norm = false ){
+ RegexPattern pattern( reg, icase, newline, usemigemo, wchar, norm );
+ return match( pattern, target, offset );
+ }
- bool exec( const std::string& target, const size_t offset );
- bool exec( const std::string reg, const std::string& target, const size_t offset, const bool icase,
- const bool newline, const bool usemigemo, const bool wchar );
+ // マッチした文字列と \0〜\9 を置換する
+ std::string replace( const std::string& repstr );
- int pos( const size_t num );
- std::string str( const size_t num );
+ int pos( const size_t num ) const;
+ std::string str( const size_t num ) const;
};
}
diff --git a/src/jdlib/jdsocket.cpp b/src/jdlib/jdsocket.cpp
new file mode 100644
index 00000000..ee8539d8
--- /dev/null
+++ b/src/jdlib/jdsocket.cpp
@@ -0,0 +1,567 @@
+// ライセンス: GPL2
+
+#ifdef _WIN32
+# ifndef WINVER
+# define WINVER 0x0501 // require Windows XP or Server 2003 for getaddrinfo
+# endif
+#endif
+
+//#define _DEBUG
+#include "jddebug.h"
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef _WIN32
+# include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# ifdef HAVE_WSPIAPI_H
+# include <wspiapi.h>
+# endif
+# include <process.h>
+#else
+# include <arpa/inet.h>
+# include <sys/socket.h>
+# include <netdb.h>
+#endif
+#ifdef _DEBUG
+# include <iomanip>
+#endif
+
+#include "jdsocket.h"
+#include "miscmsg.h"
+#include "miscutil.h"
+
+#include "config/globalconf.h"
+
+
+#ifdef _WIN32
+inline bool SOC_ISVALID( unsigned int _soc ){ return _soc != INVALID_SOCKET; }
+#else
+inline bool SOC_ISVALID( int _soc ){ return _soc >= 0; }
+#define INVALID_SOCKET -1
+#endif
+
+
+
+enum{
+ SOCKET_OK = 0,
+ SOCKET_ERR = -1,
+};
+
+inline bool is_ipaddress( const char* addr )
+{
+#ifdef _WIN32
+ struct sockaddr_storage buf;
+ int size = sizeof( buf );
+
+ if( !WSAStringToAddressA( (LPSTR)addr, AF_INET, NULL, (LPSOCKADDR)&buf, &size )
+ || !WSAStringToAddressA( (LPSTR)addr, AF_INET6, NULL, (LPSOCKADDR)&buf, &size ) ){
+ return true;
+ }
+#else
+ unsigned char buf[ sizeof( struct in6_addr) ];
+
+ if( inet_aton( addr, (struct in_addr *)&buf )
+ || inet_pton( AF_INET6, addr, &buf ) ){
+ return true;
+ }
+#endif
+ return false;
+}
+
+
+inline std::string cafile()
+{
+ std::string capath = CONFIG::get_root_cafile();
+#ifdef _WIN32
+ if( capath[ 0 ] == '/' ){
+ char buf[ MAX_PATH ];
+ char *pos;
+ GetModuleFileName( NULL, buf, MAX_PATH );
+ if( ( pos = strrchr( buf, '\\' ) ) ){
+ *pos = '\0';
+ if( ( pos = strrchr( buf, '\\' ) ) && memcmp( pos, "\\bin\0", 5 ) == 0 ){
+ capath = std::string( buf, pos - buf )
+ + MISC::replace_str( capath, "/", "\\" );
+ }
+ }
+ }
+#endif
+ return capath;
+}
+
+
+#if defined (USE_GNUTLS)
+# include "jdsocketgnutls.cpp"
+#elif defined (USE_OPENSSL)
+# include "jdsocketopenssl.cpp"
+#elif defined (USE_NSS)
+# include "jdsocketnss.cpp"
+#endif
+
+
+using namespace JDLIB;
+
+
+Socket::Socket( bool *const stop, const bool async )
+ : m_stop( stop )
+ , m_async( async )
+ , m_tout( 0 )
+ , m_soc( INVALID_SOCKET )
+ , m_tls( 0 )
+{
+ // nothing to do
+}
+
+
+Socket::~Socket()
+{
+ if( SOC_ISVALID( m_soc ) ){
+ close();
+ }
+}
+
+
+bool Socket::connect( const std::string& hostname, const std::string& port, const bool use_ipv6 )
+{
+#ifdef _DEBUG
+ std::cout << "Socket::connect" << std::endl;
+#endif
+
+ bool ret = false;
+ int optval = 0;
+ socklen_t optlen = sizeof( int );
+
+ // addrinfo 取得
+ struct addrinfo hints, *ainf=0;
+ memset( &hints, 0, sizeof( addrinfo ) );
+ if( use_ipv6 ){
+ hints.ai_family = AF_UNSPEC;
+#ifndef _WIN32
+ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+#endif
+ }
+ else hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+
+ int err = getaddrinfo( hostname.c_str(), port.c_str(), &hints, &ainf );
+ if( err ) {
+ m_errmsg = "getaddrinfo failed: " + hostname + ":" + port;
+ goto EXIT_CONNECT;
+ }
+
+#ifdef _DEBUG
+ std::cout << "host=" << hostname
+ << " ip=" << inet_ntoa( ( ( sockaddr_in* )( ainf->ai_addr ) )->sin_addr ) << std::endl;
+#endif
+
+ // ソケット作成
+ m_soc = socket( ainf->ai_family, ainf->ai_socktype, ainf->ai_protocol );
+ if( ! SOC_ISVALID( m_soc ) ){
+ m_errmsg = "socket failed";
+ goto EXIT_CONNECT;
+ }
+
+ // ソケットを非同期に設定
+ if( m_async ){
+#ifdef _WIN32
+ unsigned long flags = 0;
+ if ( ioctlsocket( m_soc, FIONBIO, &flags) != 0 )
+#else
+ int flags;
+ flags = fcntl( m_soc, F_GETFL, 0);
+ if( flags == -1 || fcntl( m_soc, F_SETFL, flags | O_NONBLOCK ) < 0 )
+#endif
+ {
+ m_errmsg = "fcntl failed";
+ goto EXIT_CONNECT;
+ }
+ }
+
+ // connect peer
+ err = ::connect( m_soc, ainf->ai_addr, ainf->ai_addrlen );
+ if( err ){
+
+ // ノンブロックでまだ接続中
+#ifdef _WIN32
+ if ( ! m_async || WSAGetLastError() != WSAEWOULDBLOCK )
+#else
+ if ( ! m_async || errno != EINPROGRESS )
+#endif
+ {
+ m_errmsg = "connect failed: " + hostname + ":" + port;
+ goto EXIT_CONNECT;
+ }
+ }
+
+ // connect待ち
+ if( ! wait_fds( false ) ){
+ m_errmsg = "connect timeout";
+ goto EXIT_CONNECT;
+ }
+
+ // connectが成功したかチェック
+ if(
+#ifdef _WIN32
+ getsockopt( m_soc, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen ) != 0
+#else
+ getsockopt( m_soc, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen ) < 0
+#endif
+ || optval ){
+ m_errmsg = "connect(getsockopt) failed: " + hostname + ":" + port;
+ goto EXIT_CONNECT;
+ }
+
+ ret = true;
+
+EXIT_CONNECT:
+ // addrinfo開放
+ if( ainf ) freeaddrinfo( ainf );
+
+ return ret;
+}
+
+
+
+bool Socket::socks_handshake( const std::string& hostname, const std::string& port, const int protocol )
+{
+#ifdef _DEBUG
+ std::cout << "Socket::socks_handshake" << std::endl;
+#endif
+
+ bool ret = false;
+
+ // addrinfo 取得
+ uint32_t addr = 0;
+ if( protocol == PROXY_SOCKS4 /*|| protocol == PROXY_SOCKS5*/ ){
+ struct addrinfo hints, *ainf=0;
+ memset( &hints, 0, sizeof( addrinfo ) );
+ // XXX SOCKS5対応の時にIPv6もサポートが必要
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+
+ int err = getaddrinfo( hostname.c_str(), port.c_str(), &hints, &ainf );
+ if( err ) {
+ m_errmsg = "getaddrinfo failed: " + hostname + ":" + port;
+ return ret;
+ }
+
+#ifdef _DEBUG
+ std::cout << "host=" << hostname
+ << " ip=" << inet_ntoa( ( ( sockaddr_in* )( ainf->ai_addr ) )->sin_addr ) << std::endl;
+#endif
+
+ addr = *(uint32_t*)&( ( sockaddr_in* )( ainf->ai_addr ) )->sin_addr;
+ freeaddrinfo( ainf );
+ }
+
+ // ポート番号変換
+ int num_port = atoi( port.c_str() );
+ if( num_port < 0 || num_port >= 0x10000 ){
+ m_errmsg = "invlid port number: " + hostname + ":" + port;
+ return ret;
+ }
+
+ char msgbuf[ 100 ];
+ char *p = msgbuf;
+ switch( protocol ){
+
+ case PROXY_SOCKS4:
+ *p++ = 4; // SOCKS Version
+ *p++ = 1; // TCP/IP Stream
+ *p++ = ( num_port >> 8 ) & 0xff;
+ *p++ = num_port & 0xff;
+ *p++ = addr & 0xff;
+ *p++ = ( addr >> 8 ) & 0xff;
+ *p++ = ( addr >> 16 ) & 0xff;
+ *p++ = ( addr >> 24 ) & 0xff;
+ *p++ = 0;
+ break;
+
+ case PROXY_SOCKS4A:
+ *p++ = 4; // SOCKS Version
+ *p++ = 1; // TCP/IP Stream
+ *p++ = ( num_port >> 8 ) & 0xff;
+ *p++ = num_port & 0xff;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 1;
+ *p++ = 0;
+ for( size_t i = 0; i <= hostname.length(); ++i )
+ *p++ = *( hostname.c_str() + i );
+ break;
+ default:
+ // XXX SOCK5未対応
+ return ret;
+ }
+
+ if( write( msgbuf, p - msgbuf ) <= 0 ){
+ return ret;
+ }
+
+ if( read( msgbuf, 8 ) <= 0 || msgbuf[0] != 0 || msgbuf[1] != 0x5a ){
+
+ m_errmsg = "socks handshake failed";
+
+#ifdef _DEBUG
+ std::cout << "socks recieve: " << std::hex << std::setfill('0')
+ << std::setw(2) << (unsigned char)msgbuf[0] << " "
+ << std::setw(2) << (unsigned char)msgbuf[1] << " "
+ << std::setw(2) << (unsigned char)msgbuf[2] << " "
+ << std::setw(2) << (unsigned char)msgbuf[3] << " ip="
+ << std::setw(2) << (unsigned char)msgbuf[4] << " "
+ << std::setw(2) << (unsigned char)msgbuf[5] << " "
+ << std::setw(2) << (unsigned char)msgbuf[6] << " "
+ << std::setw(2) << (unsigned char)msgbuf[7] << std::endl;
+#endif
+ return ret;
+ }
+
+#ifdef _DEBUG
+ std::cout << "socks handshake done: port=" << std::hex << std::setfill('0')
+ << std::setw(2) << msgbuf[2] << " " << std::setw(2) << msgbuf[3]
+ << " ip=" << std::setw(2) << msgbuf[4] << " " << std::setw(2) << msgbuf[5]
+ << " " << std::setw(2) << msgbuf[6] << " " << std::setw(2) << msgbuf[7]
+ << std::endl;
+#endif
+ ret = true;
+
+ return ret;
+}
+
+
+
+
+void Socket::close()
+{
+#ifdef _DEBUG
+ std::cout << "Socket::close" << std::endl;
+#endif
+
+ m_errmsg = std::string();
+
+ if( m_tls ){
+
+ tls_close();
+ }
+
+ if( SOC_ISVALID( m_soc ) ){
+
+ // writefds待ち
+ // 待たないとclose()したときにfinパケットが消える?
+ wait_fds( false );
+
+ // 送信禁止
+#ifdef _WIN32
+ shutdown( m_soc, SD_SEND );
+#else
+ shutdown( m_soc, SHUT_WR );
+#endif
+
+ wait_fds( false );
+
+ // ソケットクローズ
+#ifdef _WIN32
+ closesocket( m_soc );
+#else
+ ::close( m_soc );
+#endif
+
+ m_soc = INVALID_SOCKET;
+ }
+}
+
+
+
+int Socket::write( const char* buf, const size_t bufsize )
+{
+#ifdef _DEBUG
+ std::cout << "Socket::write size=" << bufsize << std::endl;
+#endif
+
+ int ret = 0;
+
+ size_t send_size = bufsize;
+ while( send_size > 0 ){
+
+ ssize_t tmpsize;
+
+ if( m_tls ){
+ // TLS使用
+ tmpsize = tls_write( buf + bufsize - send_size, send_size );
+ if( !m_errmsg.empty() ){
+ ret = SOCKET_ERR;
+ goto EXIT_WRITE;
+ }
+ }
+ else if( SOC_ISVALID( m_soc ) ){
+
+ // writefds 待ち
+ if( ! wait_fds( false ) ){
+ m_errmsg = "send timeout";
+ ret = SOCKET_ERR;
+ goto EXIT_WRITE;
+ }
+
+#ifdef _WIN32
+ tmpsize = send( m_soc, buf + bufsize - send_size, send_size, 0 );
+ int lastError = WSAGetLastError();
+#else
+#ifdef MSG_NOSIGNAL
+ tmpsize = send( m_soc, buf + bufsize - send_size, send_size, MSG_NOSIGNAL );
+#else
+ // SolarisにはMSG_NOSIGNALが無いのでSIGPIPEをIGNOREする (FreeBSD4.11Rにもなかった)
+ signal( SIGPIPE , SIG_IGN ); /* シグナルを無視する */
+ tmpsize = send( m_soc, buf + bufsize - send_size, send_size, 0 );
+ signal(SIGPIPE,SIG_DFL); /* 念のため戻す */
+#endif // MSG_NOSIGNAL
+#endif // _WIN32
+
+#ifdef _WIN32
+ if( tmpsize == 0
+ || ( tmpsize < 0 && !( lastError == WSAEWOULDBLOCK || lastError == WSAEINTR ) ) )
+#else
+ if( tmpsize == 0
+ || ( tmpsize < 0 && !( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) ) )
+#endif
+ {
+#ifdef _WIN32
+ if( lastError == WSAECONNRESET ) m_errmsg = "connection reset by peer";
+ else m_errmsg = "send failed: error=" + MISC::itostr( lastError );
+#else
+ if( errno == ECONNRESET ) m_errmsg = "connection reset by peer";
+ else m_errmsg = "send failed: errno=" + MISC::itostr( errno );
+#endif
+ ret = SOCKET_ERR;
+ goto EXIT_WRITE;
+ }
+ }
+ else{
+ m_errmsg = "send failed: internal error";
+ ret = SOCKET_ERR;
+ goto EXIT_WRITE;
+ }
+
+ if( tmpsize > 0 ) send_size -= tmpsize;
+
+ if( *m_stop ) goto EXIT_WRITE;
+ }
+
+ ret = bufsize - send_size;
+
+EXIT_WRITE:
+ return ret;
+}
+
+
+
+int Socket::read( char* buf, const size_t bufsize )
+{
+ ssize_t ret = 0;
+
+ do {
+ if( m_tls ){
+ // SSL
+ ret = tls_read( buf, bufsize );
+ if( !m_errmsg.empty() ){
+ ret = SOCKET_ERR;
+ goto EXIT_READ;
+ }
+ }
+ else if( SOC_ISVALID( m_soc ) ){
+
+ // readfds 待ち
+ if( !wait_fds( true ) ){
+ m_errmsg = "receive timeout";
+ ret = SOCKET_ERR;
+ goto EXIT_READ;
+ }
+
+ ret = recv( m_soc, buf, bufsize, 0 );
+#ifdef _WIN32
+ int lastError = WSAGetLastError();
+ if( ret < 0 && !( lastError == WSATRY_AGAIN || lastError == WSAEWOULDBLOCK || lastError == WSAEINTR ) )
+#else
+ if( ret < 0 && !( errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) )
+#endif
+ {
+#ifdef _WIN32
+ if( lastError == WSAECONNRESET ) m_errmsg = "connection reset by peer";
+ else m_errmsg = "receive failed: error=" + MISC::itostr( lastError );
+#else
+ if( errno == ECONNRESET ) m_errmsg = "connection reset by peer";
+ else m_errmsg = "receive failed: errno=" + MISC::itostr( errno );
+#endif
+ ret = SOCKET_ERR;
+ goto EXIT_READ;
+ }
+ }
+ else{
+ m_errmsg = "receive failed: internal error";
+ ret = SOCKET_ERR;
+ goto EXIT_READ;
+ }
+
+ if( *m_stop ) goto EXIT_READ;
+
+ } while( ret < 0 );
+
+#ifdef _DEBUG
+ std::cout << "Socket::recv size=" << ret << std::endl;
+#endif
+
+EXIT_READ:
+ return ret;
+}
+
+
+//
+// sent, recv待ち
+//
+bool Socket::wait_fds( const bool fdrecv )
+{
+ if( ! m_soc || ! m_async ) return true;
+
+ int count = 0;
+ for(;;){
+
+ errno = 0;
+
+ int ret;
+ fd_set fdset;
+ FD_ZERO( &fdset );
+ FD_SET( m_soc, &fdset );
+ timeval tv = { 1, 0 };
+
+ if( fdrecv ) ret = select( m_soc + 1, &fdset, NULL, NULL, &tv );
+ else ret = select( m_soc + 1, NULL, &fdset, NULL, &tv );
+
+#ifdef _DEBUG
+// if( errno == EINTR && ret < 0 ) std::cout << "Socket::wait_fds : errno = EINTR" << std::endl;
+#endif
+ if( errno != EINTR && ret < 0 ){
+#ifdef _DEBUG
+ std::cout << "Socket::wait_fds: errno = " << errno << std::endl;
+#endif
+ MISC::ERRMSG( "select failed" );
+ break;
+ }
+
+ if( errno != EINTR && FD_ISSET( m_soc, &fdset ) ) return true;
+ if( *m_stop ) break;
+
+ if( ++count >= m_tout ) break;
+#ifdef _DEBUG
+ std::cout << "Socket::wait_fds" << ( fdrecv ? "(recv)" : "(send)" ) << " timeout = " << count << std::endl;
+#endif
+ }
+
+ return false;
+}
diff --git a/src/jdlib/jdsocket.h b/src/jdlib/jdsocket.h
new file mode 100644
index 00000000..261d56d0
--- /dev/null
+++ b/src/jdlib/jdsocket.h
@@ -0,0 +1,91 @@
+// ライセンス: GPL2
+
+
+#ifndef _JDSOCKET_H
+#define _JDSOCKET_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if defined (USE_GNUTLS)
+# include <gnutls/gnutls.h>
+#elif defined (USE_OPENSSL)
+# include <openssl/ssl.h>
+// gdkmm/device.h で定義される set_key マクロと衝突する
+# ifdef set_key
+# undef set_key
+# endif
+#elif defined (USE_NSS)
+# include <nspr/prio.h>
+#endif
+
+#include <string>
+
+namespace JDLIB
+{
+ enum{
+ PROXY_NONE = 0,
+ PROXY_HTTP,
+ PROXY_SOCKS4,
+ PROXY_SOCKS4A,
+ PROXY_SOCKS5,
+ PROXY_SOCKS5H
+ };
+
+ class Socket
+ {
+ std::string m_errmsg;
+ std::string m_tls_proto;
+ volatile bool *m_stop;
+ bool m_async;
+ long m_tout;
+ int m_soc;
+
+#if defined (USE_GNUTLS)
+ gnutls_session_t m_tls;
+ bool m_terminated;
+
+#elif defined (USE_OPENSSL)
+ SSL_CTX* m_ctx;
+ SSL* m_tls;
+
+#elif defined (USE_NSS)
+ PRFileDesc *m_tls;
+
+#else
+#error No TLS library specified.
+#endif
+
+ public:
+
+ Socket( bool *const stop, const bool async = true );
+ ~Socket();
+
+ std::string& get_errmsg(){ return m_errmsg; }
+ void set_timeout( const long timeout ){ m_tout = timeout; }
+
+ bool connect( const std::string& host, const std::string& port, const bool use_ipv6 );
+ void close();
+
+ int write( const char* buf, const size_t bufsize );
+ int read( char* buf, const size_t bufsize );
+
+ bool tls_handshake( const std::string& hostname, const bool verify );
+ bool socks_handshake( const std::string& hostname, const std::string& port, const int protocol );
+
+ private:
+ int tls_write( const char* buf, const size_t length );
+ int tls_read( char* buf, const size_t bufsize );
+ void tls_close();
+
+ bool wait_fds( const bool fdrecv );
+ };
+
+
+ void tlslib_init();
+ void tlslib_deinit();
+}
+
+#endif
+
diff --git a/src/jdlib/jdsocketgnutls.cpp b/src/jdlib/jdsocketgnutls.cpp
new file mode 100644
index 00000000..5ea7885d
--- /dev/null
+++ b/src/jdlib/jdsocketgnutls.cpp
@@ -0,0 +1,322 @@
+// ライセンス: GPL2
+
+
+#include <gnutls/x509.h>
+
+#if GNUTLS_VERSION_NUMBER < 0x020000
+#define gnutls_certificate_credentials_t gnutls_certificate_credentials
+#endif // GNUTLS_VERSION_NUMBER >= 0x020000
+
+#if GNUTLS_VERSION_NUMBER < 0x029900
+#define GNUTLS_E_PREMATURE_TERMINATION GNUTLS_E_UNEXPECTED_PACKET_LENGTH
+#endif
+
+
+using namespace JDLIB;
+
+void JDLIB::tlslib_init()
+{
+#ifdef _DEBUG
+ std::cout << "tlslib_init" << std::endl;
+#endif
+
+#ifdef _WIN32
+ WSADATA wsaData;
+ if ( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ){
+ MISC::ERRMSG( "could not startup winsock2" );
+ }
+#endif
+
+ gnutls_global_init();
+}
+
+
+void JDLIB::tlslib_deinit()
+{
+#ifdef _DEBUG
+ std::cout << "tlslib_deinit" << std::endl;
+#endif
+
+ gnutls_global_deinit();
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+}
+
+
+
+bool Socket::tls_handshake( const std::string& hostname, const bool verify )
+{
+#ifdef _DEBUG
+ std::cout << "Socket::tls_handshake" << std::endl;
+#endif
+
+ bool ret = false;
+ int err = 0;
+
+ if( !SOC_ISVALID( m_soc ) ){
+ m_errmsg = "invalid socket";
+ return ret;
+ }
+
+ if( m_tls != NULL ){
+ m_errmsg = "duplicate fuction call";
+ return ret;
+ }
+
+ m_terminated = false;
+ gnutls_certificate_credentials_t cred = 0;
+
+ gnutls_init( &m_tls, GNUTLS_CLIENT );
+
+#if GNUTLS_VERSION_NUMBER >= 0x020108
+ // gnutls >= 2.1.7 (unreleased)
+ const char* const priority ="NORMAL:%COMPAT";
+ if( ( err = gnutls_priority_set_direct( m_tls, priority, NULL ) ) != GNUTLS_E_SUCCESS ){
+ m_errmsg = "priority_set failed: ";
+ m_errmsg += gnutls_strerror( err );
+ goto EXIT_TLS_CONNECT;
+ }
+#else // GNUTLS_VERSION_NUMBER >= 0x020108
+ static const int priority_prot[] = { GNUTLS_SSL3, 0 };
+ // DEPRECATED (gnutls >= 2.1.4 gnutls =< 2.1.6)
+ // UNDEPRECATED (gnutls >= 2.1.7)
+ gnutls_set_default_priority( m_tls );
+ // _GNUTLS_GCC_ATTR_DEPRECATE (gnutls >= 2.12.0)
+ gnutls_protocol_set_priority( m_tls, priority_prot );
+#endif // GNUTLS_VERSION_NUMBER >= 0x020108
+
+ // allow the use of private ciphersuites. Server Name Indication (SNI)
+ if( !is_ipaddress( hostname.c_str() ) ){
+ gnutls_server_name_set( m_tls, GNUTLS_NAME_DNS, hostname.c_str(), hostname.length() );
+ }
+
+ if( ( err = gnutls_certificate_allocate_credentials( &cred ) ) != GNUTLS_E_SUCCESS ){
+ m_errmsg = "allocate cred failed: ";
+ m_errmsg += gnutls_strerror( err );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ if( verify && ( err = gnutls_certificate_set_x509_trust_file( cred, cafile().c_str(), GNUTLS_X509_FMT_PEM ) ) < 0 ){
+ m_errmsg = "set trust file failed: ";
+ m_errmsg += gnutls_strerror( err );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ if( ( err = gnutls_credentials_set( m_tls, GNUTLS_CRD_CERTIFICATE, cred ) ) != GNUTLS_E_SUCCESS ){
+ m_errmsg = "cred set failed: ";
+ m_errmsg += gnutls_strerror( err );
+ goto EXIT_TLS_CONNECT;
+ }
+
+#if GNUTLS_VERSION_NUMBER >= 0x030109
+ gnutls_transport_set_int( m_tls, m_soc );
+#else
+ gnutls_transport_set_ptr( m_tls, (gnutls_transport_ptr_t)m_soc );
+#endif
+
+#if GNUTLS_VERSION_NUMBER >= 0x030100
+ gnutls_handshake_set_timeout( m_tls, m_tout * 1000 );
+#endif
+
+ while ( ( err = gnutls_handshake( m_tls ) ) != GNUTLS_E_SUCCESS )
+ {
+ if ( gnutls_error_is_fatal( err ) != 0 ){
+ m_errmsg = "handshake failed: ";
+ m_errmsg += gnutls_strerror( err );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ // writefds 待ち
+ if( ! wait_fds( true ) ){
+ m_errmsg = "handshake timeout";
+ goto EXIT_TLS_CONNECT;
+ }
+ }
+
+ if( verify ){
+ unsigned int status;
+ gnutls_x509_crt_t cert;
+ const gnutls_datum_t* cert_list;
+ unsigned int cert_list_size;
+
+ // try to verify the peer's certificate
+ if( ( err = gnutls_certificate_verify_peers2( m_tls, &status ) ) < 0 ){
+ m_errmsg = "certificate verify failed: ";
+ m_errmsg += gnutls_strerror( err );
+ goto EXIT_TLS_CONNECT;
+ }
+ else if( status & GNUTLS_CERT_INVALID ){
+ m_errmsg = "certificate is not trusted";
+ goto EXIT_TLS_CONNECT;
+ }
+ else if( status & GNUTLS_CERT_SIGNER_NOT_FOUND ){
+ m_errmsg = "certificate hasn't got a known issuer";
+ goto EXIT_TLS_CONNECT;
+ }
+ else if( status & GNUTLS_CERT_REVOKED ){
+ m_errmsg = "certificate has been revoked";
+ goto EXIT_TLS_CONNECT;
+ }
+#if GNUTLS_VERSION_NUMBER >= 0x020800
+ else if( status & GNUTLS_CERT_NOT_ACTIVATED ){
+ m_errmsg = "certificate not activated yet";
+ goto EXIT_TLS_CONNECT;
+ }
+ else if( status & GNUTLS_CERT_EXPIRED ){
+ m_errmsg = "certificate has expired";
+ goto EXIT_TLS_CONNECT;
+ }
+#endif
+
+ // initialize an X.509 certificate structure.
+ if( ( err = gnutls_x509_crt_init( &cert ) ) < GNUTLS_E_SUCCESS ){
+ m_errmsg = "cert init failed";
+ m_errmsg += gnutls_strerror( err );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ if( ( cert_list = gnutls_certificate_get_peers( m_tls, &cert_list_size ) ) == NULL ){
+ m_errmsg = "No cert was found";
+ gnutls_x509_crt_deinit( cert );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ // XXX We only check the first certificate in the given chain.
+ if( ( err = gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER ) ) < GNUTLS_E_SUCCESS ){
+ m_errmsg = "error parsing certificate: ";
+ m_errmsg += gnutls_strerror( err );
+ gnutls_x509_crt_deinit( cert );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ // check if the given certificate's subject matches the given hostname.
+ if( ! gnutls_x509_crt_check_hostname( cert, hostname.c_str() ) ){
+ m_errmsg = "the cert's owner does not match target hostname '";
+ m_errmsg += hostname + "'";
+ gnutls_x509_crt_deinit( cert );
+ goto EXIT_TLS_CONNECT;
+ }
+
+#if GNUTLS_VERSION_NUMBER < 0x020800
+ // Check for time-based validity
+ time_t expire = gnutls_x509_crt_get_expiration_time( cert );
+
+ if( expire == (time_t)-1 ){
+ m_errmsg = "cert expiration date verify failed";
+ gnutls_x509_crt_deinit( cert );
+ goto EXIT_TLS_CONNECT;
+ }
+ else if( expire < time( NULL ) ){
+ m_errmsg = "cert expiration date has passed";
+ gnutls_x509_crt_deinit( cert );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ time_t activate = gnutls_x509_crt_get_activation_time( cert );
+
+ if( activate == (time_t)-1 ){
+ m_errmsg = "cert activation date verify failed";
+ gnutls_x509_crt_deinit( cert );
+ goto EXIT_TLS_CONNECT;
+ }
+ else if( activate > time( NULL ) ){
+ m_errmsg = "cert not activated yet";
+ gnutls_x509_crt_deinit( cert );
+ goto EXIT_TLS_CONNECT;
+ }
+#endif
+
+ gnutls_x509_crt_deinit( cert );
+ }
+
+
+#ifdef _DEBUG
+ std::cout << gnutls_protocol_get_name( gnutls_protocol_get_version( m_tls ) )
+ << " " << gnutls_cipher_suite_get_name( gnutls_kx_get( m_tls ),
+ gnutls_cipher_get( m_tls ), gnutls_mac_get( m_tls ) )
+ << std::endl;
+#endif
+
+ ret = true;
+
+EXIT_TLS_CONNECT:
+
+ if( cred ) gnutls_certificate_free_credentials( cred );
+
+ return ret;
+}
+
+
+
+void Socket::tls_close()
+{
+ int ret;
+
+ while( ( ret = gnutls_bye( m_tls, GNUTLS_SHUT_RDWR ) ) != GNUTLS_E_SUCCESS ){
+
+ if( ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED ){
+ if( !m_terminated )
+ MISC::ERRMSG( std::string("TLS shutdown failed: ") + gnutls_strerror( ret ) );
+ break;
+ }
+
+ // readfds 待ち
+ if( !wait_fds( false ) ){
+ MISC::ERRMSG( "TLS shutdown timeout" );
+ break;
+ }
+ }
+
+ gnutls_deinit( m_tls );
+ m_terminated = false;
+ m_tls = NULL;
+}
+
+int Socket::tls_write( const char* buf, const size_t length )
+{
+ int tmpsize = gnutls_record_send( m_tls, buf, length );
+
+ if( tmpsize < 0 ){
+ if( tmpsize != GNUTLS_E_AGAIN ){
+ m_errmsg = "tls_write failed: ";
+ m_errmsg += gnutls_strerror( tmpsize );
+ }
+
+ // readfds 待ち
+ else if( !wait_fds( false ) ){
+ m_errmsg = "send timeout";
+ }
+ }
+
+ return tmpsize;
+}
+
+
+int Socket::tls_read( char* buf, const size_t bufsize )
+{
+ int ret = 0;
+ if( !m_terminated ){
+
+ ret = gnutls_record_recv( m_tls, buf, bufsize );
+ if( ret == GNUTLS_E_PREMATURE_TERMINATION ){
+ ret = 0;
+ m_terminated = true;
+ }
+ else if( ret < 0 ){
+ if( ret != GNUTLS_E_AGAIN ){
+ m_errmsg = "tls_read failed: ";
+ m_errmsg += gnutls_strerror( ret );
+ }
+
+ // readfds 待ち
+ else if( !wait_fds( true ) ){
+ m_errmsg = "receive timeout";
+ }
+ }
+ }
+
+ return ret;
+}
+
diff --git a/src/jdlib/jdsocketnss.cpp b/src/jdlib/jdsocketnss.cpp
new file mode 100644
index 00000000..e6b7079d
--- /dev/null
+++ b/src/jdlib/jdsocketnss.cpp
@@ -0,0 +1,277 @@
+// ライセンス: GPL2
+
+
+// NSPR include files
+#include <nspr/prerror.h>
+#include <nspr/prinit.h>
+// Private API, to turn a POSIX file descriptor into an NSPR handle.
+#include <nspr/private/pprio.h>
+
+// NSS include files
+#include <nss/nss.h>
+#include <nss/secmod.h>
+#include <nss/ssl.h>
+#include <nss/sslproto.h>
+#include <nss/sslerr.h>
+
+
+using namespace JDLIB;
+
+void JDLIB::tlslib_init()
+{
+#ifdef _DEBUG
+ std::cout << "tlslib_init" << std::endl;
+#endif
+
+#ifdef _WIN32
+ WSADATA wsaData;
+ if ( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ){
+ MISC::ERRMSG( "could not startup winsock2" );
+ }
+#endif
+
+ PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 32 );
+ NSS_NoDB_Init( 0 );
+ SSL_OptionSetDefault( SSL_NO_CACHE, PR_TRUE );
+ //SSL_OptionSetDefault( SSL_ENABLE_SESSION_TICKETS, PR_TRUE );
+ NSS_SetDomesticPolicy();
+
+ // Initialize the trusted certificate store.
+ const char *const module_name = "library=libnssckbi.so name=\"Root Certs\"";
+ SECMODModule *module = SECMOD_LoadUserModule( (char *)module_name, NULL, PR_FALSE );
+ if( module == NULL || !module->loaded ) {
+ std::string errmsg = "NSPR: ";
+ errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ //PR_ErrorToName( PR_GetError() );
+ MISC::ERRMSG( errmsg );
+ if( module ) SECMOD_DestroyModule( module );
+ }
+}
+
+
+void JDLIB::tlslib_deinit()
+{
+#ifdef _DEBUG
+ std::cout << "tlslib_deinit" << std::endl;
+#endif
+
+ SSL_ClearSessionCache();
+ NSS_Shutdown();
+ PR_Cleanup();
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+}
+
+
+static SECStatus PR_CALLBACK cert_hook( void *arg, PRFileDesc *fd )
+{
+ (void)fd;
+ (void)arg;
+ return SECSuccess;
+}
+
+
+
+bool Socket::tls_handshake( const std::string& hostname, const bool verify )
+{
+#ifdef _DEBUG
+ std::cout << "Socket::tls_handshake" << std::endl;
+#endif
+
+ bool ret = false;
+
+ if( !SOC_ISVALID( m_soc ) ){
+ m_errmsg = "invalid socket";
+ return ret;
+ }
+
+ if( m_tls != NULL ){
+ m_errmsg = "duplicate fuction call";
+ return ret;
+ }
+
+
+#ifdef SSL_LIBRARY_VERSION_TLS_1_2
+ SSLVersionRange sslver = { SSL_LIBRARY_VERSION_TLS_1_0, SSL_LIBRARY_VERSION_TLS_1_2 };
+#elif defined SSL_LIBRARY_VERSION_TLS_1_1
+ SSLVersionRange sslver = { SSL_LIBRARY_VERSION_TLS_1_0, SSL_LIBRARY_VERSION_TLS_1_1 };
+#else
+ SSLVersionRange sslver = { SSL_LIBRARY_VERSION_3_0, SSL_LIBRARY_VERSION_TLS_1_0 };
+#endif
+
+ PRFileDesc *prfd;
+
+ // setup sockets
+ if( !( prfd = PR_ImportTCPSocket( m_soc ) ) ){
+ m_errmsg = "Unable to convert socket: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ if( m_async ){
+ PRSocketOptionData sock_opt;
+ sock_opt.option = PR_SockOpt_Nonblocking;
+ sock_opt.value.non_blocking = PR_TRUE;
+ if( PR_SetSocketOption( prfd, &sock_opt ) != PR_SUCCESS ){
+ m_errmsg = "Unable to non blocking connection :";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+ }
+
+ if( !( m_tls = SSL_ImportFD( NULL, prfd ) ) ){
+ m_errmsg = "Unable to import SSL FileDesc: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+ prfd = NULL;
+
+ // setup SSL Options
+ if( SSL_OptionSet( m_tls, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE ) != SECSuccess ){
+ m_errmsg = "Unable to setup handshake mode: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+ if( SSL_OptionSet( m_tls, SSL_ENABLE_FDX, PR_TRUE ) != SECSuccess ){
+ m_errmsg = "Unable to setup full duplex mode: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+ if( !verify && SSL_BadCertHook( m_tls, cert_hook, NULL ) != SECSuccess ){
+ m_errmsg = "Unable to register certificate check hook: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+ if( SSL_VersionRangeSet( m_tls, &sslver) != SECSuccess ){
+ m_errmsg = "Unable to register protocol version range: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ // start SSL/TLS negotiation
+ if( SSL_ResetHandshake( m_tls, PR_FALSE ) != SECSuccess ){
+ m_errmsg = "Unable to reset secure handshake: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ if( !is_ipaddress( hostname.c_str() ) &&
+ SSL_SetURL( m_tls, hostname.c_str() ) != SECSuccess ){
+ m_errmsg = "Unable to register target host: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ // Make the handshake happen now
+ while( SSL_ForceHandshakeWithTimeout( m_tls, PR_SecondsToInterval( m_tout ) ) != SECSuccess ){
+ // PR_WOULD_BLOCK_ERROR in non-blocking mode is not an error
+ if( PR_GetError() != PR_WOULD_BLOCK_ERROR ){
+ m_errmsg = "Unable to secure negotiation: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ // writefds待ち
+ if( ! wait_fds( true ) ){
+ m_errmsg = "handshake timeout";
+ goto EXIT_TLS_CONNECT;
+ }
+ }
+
+#ifdef _DEBUG
+ SSLChannelInfo channel;
+ if( SSL_GetChannelInfo( m_tls, &channel, sizeof channel ) != SECSuccess ||
+ channel.length != sizeof channel || ! channel.cipherSuite ){
+ m_errmsg = "Unable to get ChannelInfo: ";
+ m_errmsg += PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ const char *tlsver;
+ switch( channel.protocolVersion ){
+ case SSL_LIBRARY_VERSION_2: tlsver = "SSLv2"; break;
+ case SSL_LIBRARY_VERSION_3_0: tlsver = "SSLv3"; break;
+ case SSL_LIBRARY_VERSION_TLS_1_0: tlsver = "TLS1.0"; break;
+#ifdef SSL_LIBRARY_VERSION_TLS_1_1
+ case SSL_LIBRARY_VERSION_TLS_1_1: tlsver = "TLS1.1"; break;
+#endif
+#ifdef SSL_LIBRARY_VERSION_TLS_1_2
+ case SSL_LIBRARY_VERSION_TLS_1_2: tlsver = "TLS1.2"; break;
+#endif
+#ifdef SSL_LIBRARY_VERSION_TLS_1_3
+ case SSL_LIBRARY_VERSION_TLS_1_3: tlsver = "TLS1.3"; break;
+#endif
+ default: tlsver = "SSL/TLS";
+ }
+
+ SSLCipherSuiteInfo suite;
+ if( SSL_GetCipherSuiteInfo( channel.cipherSuite, &suite, sizeof suite ) == SECSuccess )
+ std::cout << tlsver << " " << suite.cipherSuiteName << " connected." << std::endl;
+ else std::cout << tlsver << " connected." << std::endl;
+#endif
+
+ ret = true;
+
+EXIT_TLS_CONNECT:
+
+ if( prfd ) PR_Close( prfd );
+
+ return ret;
+}
+
+
+void Socket::tls_close()
+{
+ if( PR_Shutdown( m_tls, PR_SHUTDOWN_BOTH ) != PR_SUCCESS ){
+ MISC::ERRMSG( std::string( "TLS shutdown failed: " )
+ + PR_ErrorToString( PR_GetError(), PR_LANGUAGE_I_DEFAULT ) );
+ }
+ PR_Close( m_tls );
+ m_soc = INVALID_SOCKET;
+ m_tls = NULL;
+}
+
+
+int Socket::tls_write( const char* buf, const size_t length )
+{
+ ssize_t tmpsize = PR_Write( m_tls, buf, length );
+
+ if( tmpsize < 0 ){
+ PRErrorCode err = PR_GetError();
+ if( err != PR_WOULD_BLOCK_ERROR ){
+ m_errmsg = "PR_Write failed: ";
+ m_errmsg += PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT );
+ }
+
+ // writefds 待ち
+ else if( ! wait_fds( true ) ){
+ m_errmsg = "send timeout";
+ }
+ }
+
+ return tmpsize;
+}
+
+
+int Socket::tls_read( char* buf, const size_t bufsize )
+{
+ ssize_t ret = PR_Read( m_tls, buf, bufsize );
+
+ if( ret < 0 ){
+ PRErrorCode err = PR_GetError();
+ if( err != PR_WOULD_BLOCK_ERROR ){
+ m_errmsg = "PR_Read failed: ";
+ m_errmsg += PR_ErrorToString( err, PR_LANGUAGE_I_DEFAULT );
+ }
+
+ // writefds 待ち
+ else if( ! wait_fds( true ) ){
+ m_errmsg = "receive timeout";
+ }
+ }
+
+ return ret;
+}
+
diff --git a/src/jdlib/jdsocketopenssl.cpp b/src/jdlib/jdsocketopenssl.cpp
new file mode 100644
index 00000000..a63ee2fa
--- /dev/null
+++ b/src/jdlib/jdsocketopenssl.cpp
@@ -0,0 +1,245 @@
+// ライセンス: GPL2
+
+#include <openssl/err.h>
+#include <openssl/conf.h>
+
+using namespace JDLIB;
+
+void JDLIB::tlslib_init()
+{
+#ifdef _DEBUG
+ std::cout << "tlslib_init" << std::endl;
+#endif
+
+#ifdef _WIN32
+ WSADATA wsaData;
+ if ( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ){
+ MISC::ERRMSG( "could not startup winsock2" );
+ }
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100003L
+ SSL_library_init();
+#else
+ OPENSSL_init_ssl( 0, NULL );
+ OPENSSL_no_config();
+ OpenSSL_add_ssl_algorithms();
+#endif
+ SSL_load_error_strings();
+}
+
+
+void JDLIB::tlslib_deinit()
+{
+#ifdef _DEBUG
+ std::cout << "tlslib_deinit" << std::endl;
+#endif
+
+ EVP_cleanup();
+ ERR_free_strings();
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+}
+
+
+inline const char* ssllib_errstr()
+{
+ return ERR_reason_error_string( ERR_get_error() );
+}
+
+static std::string tls_get_errstr( const int error ){
+ std::string str_err;
+
+ switch( error ){
+ case SSL_ERROR_NONE: str_err = "no error"; break;
+ case SSL_ERROR_SSL: str_err = ssllib_errstr(); break;
+ case SSL_ERROR_SYSCALL: str_err = "syscall errno=" + MISC::itostr( errno ); break;
+ case SSL_ERROR_ZERO_RETURN: str_err = "zero return"; break;
+ case SSL_ERROR_WANT_CONNECT: str_err = "want connect"; break;
+ case SSL_ERROR_WANT_ACCEPT: str_err = "want accept"; break;
+ case SSL_ERROR_WANT_X509_LOOKUP: str_err = "want x509 lookup"; break;
+ }
+
+ return str_err;
+}
+
+
+bool Socket::tls_handshake( const std::string& hostname, const bool verify )
+{
+#ifdef _DEBUG
+ std::cout << "Socket::tls_handshake" << std::endl;
+#endif
+
+ bool ret = false;
+ int err = 0;
+
+ if( !SOC_ISVALID( m_soc ) ){
+ m_errmsg = "invalid socket";
+ goto EXIT_TLS_CONNECT;
+ }
+
+ if( m_tls != NULL ){
+ m_errmsg = "duplicate fuction call";
+ goto EXIT_TLS_CONNECT;
+ }
+
+
+ if( !( m_ctx = SSL_CTX_new( SSLv23_client_method() ) ) ){
+ m_errmsg = "SSL_CTX_new failed: ";
+ m_errmsg += ssllib_errstr();
+ goto EXIT_TLS_CONNECT;
+ }
+
+ //SSL_CTX_set_options( m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 );
+
+ if( verify ){
+ // load the trusted client CA certificate into context
+ if( SSL_CTX_load_verify_locations( m_ctx, cafile().c_str(), NULL) != 1 ){
+ m_errmsg = "load_verify_location failed: ";
+ m_errmsg += ssllib_errstr();
+ goto EXIT_TLS_CONNECT;
+ }
+
+ SSL_CTX_set_verify( m_ctx, SSL_VERIFY_PEER, NULL );
+ SSL_CTX_set_verify_depth( m_ctx, 4 );
+ }
+
+ if( !m_tout ) SSL_CTX_set_timeout( m_ctx, m_tout );
+
+ if( !( m_tls = SSL_new( m_ctx ) ) ){
+ m_errmsg = "SSL_new failed: ";
+ m_errmsg += ssllib_errstr();
+ goto EXIT_TLS_CONNECT;
+ }
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if( !is_ipaddress( hostname.c_str() ) &&
+ ( err = SSL_set_tlsext_host_name( m_tls, hostname.c_str() ) ) != 1 ){
+ m_errmsg = "set_tlsext_host_name failed: ";
+ m_errmsg += ssllib_errstr();
+ goto EXIT_TLS_CONNECT;
+ }
+#endif
+
+ if( !( err = SSL_set_fd( m_tls, m_soc ) ) ){
+ m_errmsg = "set_fd failed: ";
+ m_errmsg += ssllib_errstr();
+ goto EXIT_TLS_CONNECT;
+ }
+
+ SSL_set_connect_state( m_tls );
+
+ while( ( err = SSL_do_handshake( m_tls ) ) != 1 ){
+ bool want_read;
+
+ err = SSL_get_error( m_tls, err );
+ if( err == SSL_ERROR_WANT_READ ) want_read = true;
+ else if( err == SSL_ERROR_WANT_WRITE ) want_read = false;
+ else{
+ m_errmsg = "SSL_do_handshake failed: ";
+ m_errmsg += tls_get_errstr( err );
+ goto EXIT_TLS_CONNECT;
+ }
+
+ // writefds 待ち
+ if( ! wait_fds( want_read ) ){
+ m_errmsg = "SSL_do_handshake timeout";
+ goto EXIT_TLS_CONNECT;
+ }
+ }
+
+#ifdef _DEBUG
+ std::cout << SSL_get_version( m_tls ) << " (OpenSSL)" << std::endl;;
+#endif
+
+ ret = true;
+
+EXIT_TLS_CONNECT:
+
+ return ret;
+}
+
+
+void Socket::tls_close()
+{
+ int ret;
+
+ while( ( ret = SSL_shutdown( m_tls ) ) != 1 ){
+ bool want_read = true;
+
+ if( ret != 0 ){
+ ret = SSL_get_error( m_tls, ret );
+ if( ret == 0 || ret == SSL_ERROR_WANT_READ ) want_read = true;
+ else if( ret == SSL_ERROR_WANT_WRITE ) want_read = false;
+ else{
+ if( ret != SSL_ERROR_SYSCALL || errno != 0 ){
+ MISC::ERRMSG( "SSL_shutdown failed: " + tls_get_errstr( ret ) );
+ }
+ break;
+ }
+ }
+
+ // writefds 待ち
+ if( ! wait_fds( want_read ) ){
+ MISC::ERRMSG( "SSL_shutdown timeout" );
+ break;
+ }
+ }
+ SSL_free( m_tls );
+ SSL_CTX_free( m_ctx );
+
+ m_tls = NULL;
+}
+
+
+int Socket::tls_write( const char* buf, const size_t length )
+{
+ ssize_t tmpsize = SSL_write( m_tls, buf, length );
+
+ if( tmpsize < 0 ){
+ bool want_read;
+
+ int ret = SSL_get_error( m_tls, tmpsize );
+ if( ret == SSL_ERROR_WANT_READ ) want_read = true;
+ else if( ret == SSL_ERROR_WANT_WRITE ) want_read = false;
+ else{
+ m_errmsg = "SSL_write failed: " + tls_get_errstr( ret );
+ return tmpsize;
+ }
+
+ // writefds 待ち
+ if( ! wait_fds( want_read ) ){
+ m_errmsg = "send timeout";
+ }
+ }
+
+ return tmpsize;
+}
+
+
+int Socket::tls_read( char* buf, const size_t bufsize )
+{
+ ssize_t tmpsize = SSL_read( m_tls, buf, bufsize );
+
+ if( tmpsize < 0 ){
+ bool want_read;
+
+ int ret = SSL_get_error( m_tls, tmpsize );
+ if( ret == SSL_ERROR_WANT_READ ) want_read = true;
+ else if( ret == SSL_ERROR_WANT_WRITE ) want_read = false;
+ else{
+ m_errmsg = "SSL_read failed: " + tls_get_errstr( ret );
+ return tmpsize;
+ }
+
+ // writefds 待ち
+ if( ! wait_fds( want_read ) ){
+ m_errmsg = "receive timeout";
+ }
+ }
+
+ return tmpsize;
+}
+
diff --git a/src/jdlib/loader.cpp b/src/jdlib/loader.cpp
index 983a1d21..2a84529f 100644
--- a/src/jdlib/loader.cpp
+++ b/src/jdlib/loader.cpp
@@ -1,9 +1,5 @@
// ライセンス: GPL2
-#ifdef _WIN32
-// require Windows XP or Server 2003 for getaddrinfo
-#define WINVER 0x0501
-#endif
//#define _DEBUG
//#define _DEBUG_CHUNKED
@@ -17,7 +13,7 @@
#include "loader.h"
#include "miscmsg.h"
#include "miscutil.h"
-#include "ssl.h"
+#include "jdsocket.h"
#ifdef _DEBUG_TIME
#include "misctime.h"
@@ -33,25 +29,8 @@
#include <mutex>
#include <sstream>
-#include <errno.h>
-#include <fcntl.h>
-#ifdef _WIN32
-#include <process.h>
-#else
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#endif
-#include <signal.h>
-
#include <glibmm.h>
-#ifdef _WIN32
-// _soc : SOCKET (unsigned int)
-#define SOC_ISVALID(_soc) ( (_soc) != INVALID_SOCKET )
-#else
-// _soc : int
-#define SOC_ISVALID(_soc) ( (_soc) >= 0 )
-#endif
constexpr int MAX_LOADER = 10; // 最大スレッド数
constexpr int MAX_LOADER_SAMEHOST = 2; // 同一ホストに対して実行できる最大スレッド数
@@ -59,10 +38,6 @@ constexpr size_t LNG_BUF_MIN = 1 * 1024; // 読み込みバッファの最小値
constexpr long TIMEOUT_MIN = 1; // タイムアウトの最小値 (秒)
-#ifdef _WIN32
-bool initialized_loader = false;
-#endif
-
//
// トークンとスレッド起動待ちキュー
@@ -242,12 +217,6 @@ void JDLIB::check_loader_alive()
MISC::ERRMSG( "queue of loaders are not empty." );
assert( false );
}
-
-#ifdef _WIN32
- if ( initialized_loader ){
- WSACleanup();
- }
-#endif
}
@@ -261,8 +230,7 @@ using namespace JDLIB;
// low_priority = true の時はスレッド起動待ち状態になった時に、起動順のプライオリティを下げる
//
Loader::Loader( const bool low_priority )
- : m_addrinfo( 0 ),
- m_stop( false ),
+ : m_stop( false ),
m_loading( false ),
m_low_priority( low_priority ),
m_buf( 0 ),
@@ -274,16 +242,6 @@ Loader::Loader( const bool low_priority )
std::cout << "Loader::Loader : loader was created.\n";
#endif
-#ifdef _WIN32
- if ( !initialized_loader ){
- WSADATA wsaData;
- if ( WSAStartup(MAKEWORD(2,0), &wsaData) != 0 ){
- MISC::ERRMSG( "could not startup winsock2" );
- }
- initialized_loader = true;
- }
-#endif
-
clear();
}
@@ -422,65 +380,67 @@ bool Loader::run( SKELETON::Loadable* cb, const LOADERDATA& data_in )
}
m_data.host = m_data.url.substr( i, i2 - i );
- i = i2; m_data.path = m_data.url.substr( i2 );
+ m_data.path = m_data.url.substr( i2 );
// ポートセット
+ // プロトコルを見て自動決定
+ // http
+ if( m_data.protocol == "http://" ) m_data.port = 80;
+
+ // https
+ else if( m_data.protocol == "https://" ){
+ m_data.use_ssl = true;
+ m_data.port = 443;
+ }
+
+ // その他
+ else{
+ m_data.code = HTTP_ERR;
+ m_data.str_code = "unknown protocol : " + m_data.url;
+ MISC::ERRMSG( m_data.str_code );
+ return false;
+ }
+
+ // ポート番号
+ if( data_in.port != 0 ) m_data.port = data_in.port;
+
// ホスト名の後に指定されている
if( ( i = m_data.host.find( ":" ) ) != std::string::npos ){
m_data.port = atoi( m_data.host.substr( i+1 ).c_str() );
m_data.host = m_data.host.substr( 0, i );
}
- // 明示的に指定
- else if( data_in.port != 0 ) m_data.port = data_in.port;
-
- // プロトコルを見て自動決定
- else{
-
- // http
- if( m_data.protocol.find( "http://" ) != std::string::npos )
- m_data.port = data_in.use_ssl ? 443 : 80;
-
- // https
- else if( m_data.protocol.find( "https://" ) != std::string::npos ){
- m_data.port = 443;
- }
-
- // その他
- else{
-
- m_data.code = HTTP_ERR;
- m_data.str_code = "unknown protocol : " + m_data.url;
- MISC::ERRMSG( m_data.str_code );
- return false;
- }
- }
-
- // ssl使用指定
- // HACK: don't use SSL to access 2ch via a scraping proxy
- if( data_in.use_ssl
- || ( m_data.protocol.find( "https://" ) != std::string::npos
- && m_data.host.find( ".2ch.net" ) == std::string::npos
- && m_data.host.find( ".5ch.net" ) == std::string::npos
- && m_data.host.find( ".bbspink.com" ) == std::string::npos
- )
- ){
- m_data.use_ssl = true;
- m_data.async = false;
- }
+ // 明示的にssl使用指定
+ if( data_in.use_ssl ) m_data.use_ssl = true;
// プロキシ
m_data.host_proxy = data_in.host_proxy;
-
- // 先頭に *tp:// が付いていたら取り除く
- if( ! m_data.host_proxy.empty() && m_data.host_proxy.find( "tp://" ) != std::string::npos ){
- const bool protocol = false;
- m_data.host_proxy = MISC::get_hostname( m_data.host_proxy , protocol );
+ if( ( i = m_data.host_proxy.find( "://" ) ) != std::string::npos ){
+ const std::string proto = data_in.host_proxy.substr( 0, i );
+ if( proto == "http" ) m_data.protocol_proxy = PROXY_HTTP;
+ else if( proto == "socks4" ) m_data.protocol_proxy = PROXY_SOCKS4;
+ else if( proto == "socks4a" ) m_data.protocol_proxy = PROXY_SOCKS4A;
+ else{
+ m_data.code = HTTP_ERR;
+ m_data.str_code = "unknown proxy protocol : " + proto;
+ MISC::ERRMSG( m_data.str_code );
+ return false;
+ }
+ m_data.host_proxy = m_data.host_proxy.substr( i + 3 );
}
+ else m_data.protocol_proxy = PROXY_HTTP;
+
+ // プロキシのポート番号
+ if( data_in.port_proxy != 0 ) m_data.port_proxy = data_in.port_proxy;
+
+ // ホスト名の後に指定されている
+ if( ( i = m_data.host_proxy.rfind( ":" ) ) != std::string::npos ){
+ m_data.port_proxy = atoi( m_data.host_proxy.substr( i + 1 ).c_str() );
+ m_data.host_proxy = m_data.host_proxy.substr( 0, i );
+ }
+
if( ! m_data.host_proxy.empty() ){
- m_data.port_proxy = data_in.port_proxy;
- if( m_data.port_proxy == 0 ) m_data.port_proxy = 8080;
m_data.basicauth_proxy = data_in.basicauth_proxy;
}
@@ -496,7 +456,6 @@ bool Loader::run( SKELETON::Loadable* cb, const LOADERDATA& data_in )
m_data.timeout = MAX( TIMEOUT_MIN, data_in.timeout );
m_data.ex_field = data_in.ex_field;
m_data.basicauth = data_in.basicauth;
- m_data.use_ipv6 = data_in.use_ipv6;
#ifdef _DEBUG
std::cout << "host: " << m_data.host << std::endl;
@@ -509,6 +468,7 @@ bool Loader::run( SKELETON::Loadable* cb, const LOADERDATA& data_in )
std::cout << "agent: " << m_data.agent << std::endl;
std::cout << "referer: " << m_data.referer << std::endl;
std::cout << "cookie: " << m_data.cookie_for_write << std::endl;
+ std::cout << "protocol of proxy: " << m_data.protocol_proxy << std::endl;
std::cout << "proxy: " << m_data.host_proxy << std::endl;
std::cout << "port of proxy: " << m_data.port_proxy << std::endl;
std::cout << "proxy basicauth : " << m_data.basicauth_proxy << std::endl;
@@ -561,87 +521,6 @@ void* Loader::launcher( void* dat )
}
-bool Loader::send_connect( const int soc, std::string& errmsg )
-{
- std::string authority;
- std::string msg_send;
-
- authority = m_data.host + ":" + std::to_string( m_data.port );
- msg_send = "CONNECT " + authority + " HTTP/1.1\r\nHost: " + authority + "\r\n\r\n";
- size_t send_size = strlen( msg_send.data() );
- while( send_size > 0 && !m_stop ){
- if( ! wait_recv_send( soc, false ) ){
- m_data.code = HTTP_TIMEOUT;
- errmsg = "send timeout";
- return false;
- }
-
-#ifdef _WIN32
- ssize_t tmpsize = send( soc, msg_send.data(), send_size,0);
- int lastError = WSAGetLastError();
-#else
-#ifdef MSG_NOSIGNAL
- ssize_t tmpsize = send( soc, msg_send.data(), send_size, MSG_NOSIGNAL );
-#else
- // SolarisにはMSG_NOSIGNALが無いのでSIGPIPEをIGNOREする (FreeBSD4.11Rにもなかった)
- signal( SIGPIPE , SIG_IGN ); /* シグナルを無視する */
- ssize_t tmpsize = send( soc, msg_send.data(), send_size,0);
- signal(SIGPIPE,SIG_DFL); /* 念のため戻す */
-#endif // MSG_NOSIGNAL
-#endif // _WIN32
-
-#ifdef _WIN32
- if( tmpsize == 0
- || ( tmpsize < 0 && !( lastError == WSAEWOULDBLOCK || errno == WSAEINTR ) ) ){
-#else
- if( tmpsize == 0
- || ( tmpsize < 0 && !( errno == EWOULDBLOCK || errno == EINTR ) ) ){
-#endif
-
- m_data.code = HTTP_ERR;
- errmsg = "send failed : " + m_data.url;
- return false;
- }
-
- if( tmpsize > 0 ) send_size -= tmpsize;
- }
-
- char rbuf[256];
- size_t read_size = 0;
- while( read_size < sizeof(rbuf) && !m_stop ){
-
- ssize_t tmpsize;
-
- if( !wait_recv_send( soc, true ) ){
- m_data.code = HTTP_TIMEOUT;
- errmsg = "CONNECT: read timeout in";
- return false;
- }
-
- tmpsize = recv( soc, rbuf + read_size, sizeof(rbuf) - read_size, 0 );
- if( tmpsize < 0 && errno != EINTR ){
- m_data.code = HTTP_ERR;
- errmsg = "CONNECT: recv() failed";
- return false;
- }
-
- if( tmpsize == 0 ) break;
- if( tmpsize > 0 ){
- read_size += tmpsize;
-
- const int ret = receive_header( rbuf, read_size );
- if( ret == HTTP_ERR ){
-
- m_data.code = HTTP_ERR;
- errmsg = "CONNECT: invalid header : " + m_data.url;
- return false;
- }
- else if( ret == HTTP_OK ) return true;
- }
- }
- return false;
-}
-
//
// 実際の処理部
//
@@ -650,15 +529,8 @@ void Loader::run_main()
// エラーメッセージ
std::string errmsg;
-#ifdef _WIN32
- SOCKET soc = INVALID_SOCKET; // ソケットID
-#else
- int soc = -1; // ソケットID
-#endif
bool use_proxy = ( ! m_data.host_proxy.empty() );
- JDLIB::JDSSL* ssl = NULL;
-
// 送信メッセージ作成
const std::string msg_send = create_msg_send();
@@ -668,242 +540,125 @@ void Loader::run_main()
std::cout <<"send :----------\n" << msg_send << "\n---------------\n";
#endif
- // addrinfo 取得
+ bool async = ! m_data.use_ssl || CONFIG::get_tls_nonblocking();
+ JDLIB::Socket soc( &m_stop, async );
+ soc.set_timeout( m_data.timeout );
+
+ // socket接続
+ const bool use_ipv6 = CONFIG::get_use_ipv6();
if( m_data.host_proxy.empty() ){
- m_addrinfo = get_addrinfo( m_data.host, m_data.port );
- if( ! m_addrinfo ){
+ if( ! soc.connect( m_data.host, MISC::itostr( m_data.port ), use_ipv6 ) ){
m_data.code = HTTP_ERR;
- errmsg = "getaddrinfo failed : " + m_data.url;
+ errmsg = soc.get_errmsg();
goto EXIT_LOADING;
}
}
else{
- m_addrinfo = get_addrinfo( m_data.host_proxy, m_data.port_proxy );
- if( ! m_addrinfo ){
+ if( ! soc.connect( m_data.host_proxy, MISC::itostr( m_data.port_proxy ), use_ipv6 ) ){
m_data.code = HTTP_ERR;
- errmsg = "getaddrinfo failed : " + m_data.host_proxy;
+ errmsg = soc.get_errmsg();
goto EXIT_LOADING;
}
}
- // ソケット作成
- soc = socket( m_addrinfo ->ai_family, m_addrinfo ->ai_socktype, m_addrinfo ->ai_protocol );
- if( ! SOC_ISVALID( soc ) ){
- m_data.code = HTTP_ERR;
- errmsg = "socket failed : " + m_data.url;
- goto EXIT_LOADING;
- }
-
- // ソケットを非同期に設定
- if( m_data.async ){
-#ifdef _WIN32
- u_long flags = 0;
- if ( ioctlsocket( soc, FIONBIO, &flags) != 0 ){
-#else
- int flags;
- flags = fcntl( soc, F_GETFL, 0);
- if( flags == -1 || fcntl( soc, F_SETFL, flags | O_NONBLOCK ) < 0 ){
-#endif
- m_data.code = HTTP_ERR;
- errmsg = "fcntl failed";
- goto EXIT_LOADING;
- }
- }
+ // 受信用バッファの割り当て
+ assert( m_buf == NULL );
+ m_buf = ( char* )malloc( m_lng_buf );
- // サーバにconnect
- int ret;
- ret = connect( soc, m_addrinfo ->ai_addr, m_addrinfo ->ai_addrlen );
- if( ret != 0 ){
-
- // ノンブロックでまだ接続中
-#ifdef _WIN32
- if ( !( m_data.async && WSAGetLastError() == WSAEWOULDBLOCK ) ){
-#else
- if ( !( m_data.async && errno == EINPROGRESS ) ){
-#endif
+ // Socksのハンドシェーク
+ if( use_proxy && m_data.protocol_proxy != PROXY_HTTP ){
+ if( ! soc.socks_handshake( m_data.host, MISC::itostr( m_data.port ), m_data.protocol_proxy ) ){
m_data.code = HTTP_ERR;
- if( ! use_proxy ) errmsg = "connect failed : " + m_data.host;
- else errmsg = "connect failed : " + m_data.host_proxy;
+ errmsg = soc.get_errmsg();
goto EXIT_LOADING;
}
}
- // connect待ち
- if( m_data.async ){
+ // HTTP tunneling
+ else if( use_proxy && m_data.protocol_proxy == PROXY_HTTP && m_data.use_ssl ){
- if( ! wait_recv_send( soc, false ) ){
+ // CONNECT
+ std::string msg = "CONNECT ";
+ msg += m_data.host + ":" + MISC::itostr( m_data.port ) + " HTTP/1.1\r\n";
+ msg += "Host: " + m_data.host + "\r\n";
+ msg += "Proxy-Connection: keep-alive\r\n";
+ if( ! m_data.agent.empty() ) msg += "User-Agent: " + m_data.agent + "\r\n";
+ msg += "\r\n";
- // タイムアウト
- m_data.code = HTTP_TIMEOUT;
- errmsg = "connect timeout";
- goto EXIT_LOADING;
- }
+ if( soc.write( msg.c_str(), msg.length() ) < 0 ){
- // connectが成功したかチェック
- int optval;
- socklen_t optlen = sizeof( int );
-#ifdef _WIN32
- if( getsockopt( soc, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen ) != 0 ){
-#else
- if( getsockopt( soc, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen ) < 0 ){
-#endif
m_data.code = HTTP_ERR;
- errmsg = "getsockopt failed";
+ errmsg = soc.get_errmsg();
goto EXIT_LOADING;
}
- if( optval != 0 ){
- m_data.code = HTTP_ERR;
- errmsg = "connect(getsockopt) failed";
- goto EXIT_LOADING;
- }
+ // 読み込み
+ size_t read_size = 0;
+ while( read_size < m_lng_buf && !m_stop ){
-#ifdef _DEBUG
- std::cout << "connect ok\n";
-#endif
+ ssize_t tmpsize = soc.read( m_buf + read_size, m_lng_buf - read_size );
+ if( tmpsize < 0 ){
+ m_data.code = HTTP_ERR;
+ errmsg = soc.get_errmsg();
+ goto EXIT_LOADING;
+ }
+
+ else if( tmpsize == 0 ) goto EXIT_LOADING;
+ else read_size += tmpsize;
+
+ const int ret = receive_header( m_buf, read_size );
+ if( ret == HTTP_ERR ){
+ m_data.code = HTTP_ERR;
+ errmsg = "invalid proxy header : " + m_data.url;
+ goto EXIT_LOADING;
+ }
+ else if( ret == HTTP_OK ){
+ if( m_data.code < 200 || m_data.code >= 300 ){
+ goto EXIT_LOADING;
+ }
+ break;
+ }
+ }
}
- // ssl 初期化とコネクト
+ // TLSのハンドシェーク
if( m_data.use_ssl ){
- if ( use_proxy ) {
- if ( ! send_connect( soc, errmsg ) )
- goto EXIT_LOADING;
- }
- ssl = new JDLIB::JDSSL();
- if( ! ssl->connect( soc, m_data.host.c_str() ) ){
+ if( ! soc.tls_handshake( m_data.host.c_str(), CONFIG::get_verify_cert() ) ){
m_data.code = HTTP_ERR;
- errmsg = ssl->get_errmsg() + " : " + m_data.url;
+ errmsg = soc.get_errmsg();
goto EXIT_LOADING;
}
}
// SEND 又は POST
+ if( soc.write( msg_send.c_str(), msg_send.length() ) < 0 ){
- // 通常
- if( !ssl ){
-
- size_t send_size = strlen( msg_send.data() );
- while( send_size > 0 && !m_stop ){
-
- // writefds 待ち
- if( ! wait_recv_send( soc, false ) ){
-
- // タイムアウト
- m_data.code = HTTP_TIMEOUT;
- errmsg = "send timeout";
- goto EXIT_LOADING;
- }
-
- // SEND 又は POST
-#ifdef _WIN32
- ssize_t tmpsize = send( soc, msg_send.data(), send_size,0);
- int lastError = WSAGetLastError();
-#else
-#ifdef MSG_NOSIGNAL
- ssize_t tmpsize = send( soc, msg_send.data(), send_size, MSG_NOSIGNAL );
-#else
- // SolarisにはMSG_NOSIGNALが無いのでSIGPIPEをIGNOREする (FreeBSD4.11Rにもなかった)
- signal( SIGPIPE , SIG_IGN ); /* シグナルを無視する */
- ssize_t tmpsize = send( soc, msg_send.data(), send_size,0);
- signal(SIGPIPE,SIG_DFL); /* 念のため戻す */
-#endif // MSG_NOSIGNAL
-#endif // _WIN32
-
-#ifdef _WIN32
- if( tmpsize == 0
- || ( tmpsize < 0 && !( lastError == WSAEWOULDBLOCK || errno == WSAEINTR ) ) ){
-#else
- if( tmpsize == 0
- || ( tmpsize < 0 && !( errno == EWOULDBLOCK || errno == EINTR ) ) ){
-#endif
-
- m_data.code = HTTP_ERR;
- errmsg = "send failed : " + m_data.url;
- goto EXIT_LOADING;
- }
-
- if( tmpsize > 0 ) send_size -= tmpsize;
- }
-
- if( m_stop ) goto EXIT_LOADING;
-
-#ifdef _DEBUG
- std::cout << "send ok\n";
-#endif
+ m_data.code = HTTP_ERR;
+ errmsg = soc.get_errmsg();
+ goto EXIT_LOADING;
}
- // SSL使用
- else{
-
- if( ssl->write( msg_send.data(), strlen( msg_send.data() ) ) < 0 ){
-
- m_data.code = HTTP_ERR;
- errmsg = ssl->get_errmsg() + " : " + m_data.url;
- goto EXIT_LOADING;
- }
- }
-
- // 受信用バッファを作ってメッセージ受信
- size_t mrg;
- mrg = 64; // 一応オーバーフロー避けのおまじない
- assert( m_buf == NULL );
- m_buf = ( char* )malloc( m_lng_buf + mrg );
-
- bool receiving_header;
-
#ifdef _DEBUG_TIME
MISC::start_measurement( 1 );
#endif
// 受信開始
+ bool receiving_header;
receiving_header = true;
m_data.length_current = 0;
m_data.size_data = 0;
do{
// 読み込み
size_t read_size = 0;
- while( read_size < m_lng_buf - mrg && !m_stop ){
+ while( read_size < m_lng_buf && !m_stop ){
- ssize_t tmpsize;
-
- // 通常
- if( !ssl ){
-
-#ifdef _DEBUG_TIME
- MISC::start_measurement( 0 );
-#endif
-
- // readfds 待ち
- if( !wait_recv_send( soc, true ) ){
- // タイムアウト
- m_data.code = HTTP_TIMEOUT;
- errmsg = "read timeout";
- goto EXIT_LOADING;
- }
-
- tmpsize = recv( soc, m_buf + read_size, m_lng_buf - read_size - mrg, 0 );
- if( tmpsize < 0 && errno != EINTR ){
- m_data.code = HTTP_ERR;
- errmsg = "recv() failed";
- goto EXIT_LOADING;
- }
-
-#ifdef _DEBUG_TIME
- std::cout << "size = " << tmpsize << " time = " << MISC::measurement( 0 ) << std::endl;
-#endif
- }
-
- // SSL
- else{
-
- tmpsize = ssl->read( m_buf + read_size, m_lng_buf - read_size - mrg );
- if( tmpsize < 0 ){
- m_data.code = HTTP_ERR;
- errmsg = ssl->get_errmsg() + " : " + m_data.url;
- goto EXIT_LOADING;
- }
+ ssize_t tmpsize = soc.read( m_buf + read_size, m_lng_buf - read_size );
+ if( tmpsize < 0 ){
+ m_data.code = HTTP_ERR;
+ errmsg = soc.get_errmsg();
+ goto EXIT_LOADING;
}
if( tmpsize == 0 ) break;
@@ -929,8 +684,6 @@ void Loader::run_main()
}
- m_buf[ read_size ] = '\0';
-
// 停止指定
if( m_stop ) break;
@@ -963,7 +716,7 @@ void Loader::run_main()
if( !skip_chunk( m_buf, read_size ) ){
m_data.code = HTTP_ERR;
- errmsg = "skip_chunk() failed : " + m_data.url;
+ errmsg = "skip_chunk() failed";
goto EXIT_LOADING;
}
if( ! read_size ) break;
@@ -982,7 +735,7 @@ void Loader::run_main()
else if( !unzip( m_buf, read_size ) ){
m_data.code = HTTP_ERR;
- errmsg = "unzip() failed : " + m_data.url;
+ errmsg = "unzip() failed";
goto EXIT_LOADING;
}
@@ -997,32 +750,6 @@ void Loader::run_main()
// 終了処理
EXIT_LOADING:
- // ssl クローズ
- if( ssl ){
- ssl->close();
- delete ssl;
- ssl = NULL;
- }
-
- if( SOC_ISVALID( soc ) ){
-
- // writefds待ち
- // 待たないとclose()したときにfinパケットが消える?
- if( ! wait_recv_send( soc, false ) ){
-
- // タイムアウト
- m_data.code = HTTP_TIMEOUT;
- errmsg = "send timeout";
- }
-
- // 送信禁止
-#ifdef _WIN32
- shutdown( soc, SD_SEND );
-#else
- shutdown( soc, SHUT_WR );
-#endif
- }
-
// 強制停止した場合
if( m_stop ){
#ifdef _DEBUG
@@ -1040,17 +767,7 @@ EXIT_LOADING:
}
// ソケットクローズ
- if( SOC_ISVALID( soc ) ){
-#ifdef _WIN32
- closesocket( soc );
-#else
- close( soc );
-#endif
- }
-
- // addrinfo開放
- if( m_addrinfo ) freeaddrinfo( m_addrinfo );
- m_addrinfo = NULL;
+ soc.close();
// トークン返す
return_token( this );
@@ -1067,48 +784,13 @@ EXIT_LOADING:
-//
-// addrinfo 取得
-//
-struct addrinfo* Loader::get_addrinfo( const std::string& hostname, const int port )
-{
- if( port < 0 || port > 65535 ) return NULL;
- if( hostname.empty() ) return NULL;
-
- int ret;
- struct addrinfo hints, *res;
- const int poststrlng = 256;
- char port_str[ poststrlng ];
- memset( &hints, 0, sizeof( addrinfo ) );
- if( m_data.use_ipv6 ) hints.ai_family = AF_UNSPEC;
- else hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
-
- snprintf( port_str, poststrlng, "%d", port );
- ret = getaddrinfo( hostname.c_str(), port_str, &hints, &res );
- if( ret ) {
- MISC::ERRMSG( m_data.str_code );
- return NULL;
- }
-
-#ifdef _DEBUG
- std::cout << "host = " << hostname
- << " ipv6 = " << m_data.use_ipv6
- << ", ip =" << inet_ntoa( ( ( sockaddr_in* )( res->ai_addr ) )->sin_addr ) << std::endl;
-#endif
-
- return res;
-}
-
-
-
//
// 送信メッセージ作成
//
std::string Loader::create_msg_send()
{
bool post_msg = ( !m_data.str_post.empty() && !m_data.head );
- bool use_proxy = ( ! m_data.host_proxy.empty() );
+ bool use_proxy = ! m_data.host_proxy.empty() && ! m_data.use_ssl;
std::ostringstream msg;
msg.clear();
@@ -1185,8 +867,7 @@ int Loader::receive_header( char* buf, size_t& read_size )
std::cout << "Loader::receive_header : read_size = " << read_size << std::endl;
#endif
- buf[ read_size ] = '\0';
- m_data.str_header = buf;
+ m_data.str_header.assign( buf, read_size );
size_t lng_header = m_data.str_header.find( "\r\n\r\n" );
if( lng_header != std::string::npos ) lng_header += 4;
else{
@@ -1207,11 +888,7 @@ int Loader::receive_header( char* buf, size_t& read_size )
// 残りのデータを前に移動
read_size -= lng_header;
- if( read_size ){
-
- memmove( buf, buf+ lng_header, read_size );
- buf[ read_size ] = '\0';
- }
+ if( read_size ) memmove( buf, buf + lng_header, read_size );
return HTTP_OK;
}
@@ -1268,6 +945,14 @@ bool Loader::analyze_header()
// Content-Type
m_data.contenttype = analyze_header_option( "Content-Type: " );
+ // ERROR
+ m_data.error = analyze_header_option( "ERROR: " );
+
+ // Thread-Status
+ m_data.threadstatus = 0;
+ str_tmp = analyze_header_option( "Thread-Status: " );
+ if( ! str_tmp.empty() ) m_data.threadstatus = atoi( str_tmp.c_str() );
+
// chunked か
m_use_chunk = false;
str_tmp = analyze_header_option( "Transfer-Encoding: " );
@@ -1295,7 +980,9 @@ bool Loader::analyze_header()
for( ; it != m_data.list_cookies.end(); ++it ) std::cout << "cookie = " << (*it) << std::endl;
std::cout << "location = " << m_data.location << std::endl;
- std::cout << "contenttype = " << m_data.contenttype<< std::endl;
+ std::cout << "contenttype = " << m_data.contenttype << std::endl;
+ std::cout << "error = " << m_data.error << std::endl;
+ std::cout << "threadstatus = " << m_data.threadstatus << std::endl;
if( m_use_chunk ) std::cout << "m_use_chunk = true\n";
if( m_use_zlib ) std::cout << "m_use_zlib = true\n";
@@ -1313,15 +1000,29 @@ bool Loader::analyze_header()
//
std::string Loader::analyze_header_option( const std::string& option )
{
- size_t i = 0, i2 = 0;
- i = m_data.str_header.find( option, 0 );
- if( i != std::string::npos ){
- const size_t option_length = option.length();
- i2 = m_data.str_header.find( "\r\n", i );
- if( i2 == std::string::npos ) i2 = m_data.str_header.find( "\n", i );
- if( i2 != std::string::npos ) return m_data.str_header.substr( i + option_length, i2 - ( i + option_length ) );
+ char accept[3] = { 0, 0, 0 };
+ const char ch = option[ 0 ];
+
+ if( ( ch >= 'A' && ch <= 'Z' ) || ( ch >= 'a' && ch <= 'z' ) ){
+ accept[ 0 ] = ch & ~0x20;
+ accept[ 1 ] = ch | 0x20;
+ }
+ else accept[ 0 ] = ch;
+
+ const char *p1, *p2 = m_data.str_header.c_str();
+
+ for( ; ( p1 = strpbrk( p2, accept ) ) != NULL ; p2 = p1 + 1 ){
+ if( strncasecmp( p1, option.c_str(), option.length() ) == 0 ) break;
}
+ if( p1 != NULL ){
+ p2 = strstr( p1, "\r\n" );
+ if( p2 == NULL ) p2 = strchr( p1, '\n' );
+ if( p2 != NULL ){
+ p1 += option.length();
+ return std::string( p1, p2 - p1 );
+ }
+ }
return std::string();
}
@@ -1386,19 +1087,19 @@ bool Loader::skip_chunk( char* buf, size_t& read_size )
// バッファオーバーフローのチェック
if( ( long )( m_pos_sizepart - m_str_sizepart ) >= 64 ){
- MISC::ERRMSG( "buffer over flow at skip_chunk" );
- return false;
+ m_use_chunk = false;
+ MISC::ERRMSG( "chunk specified but maybe no chunk data" );
+ return true;
}
- *( m_pos_sizepart ) = buf[ pos_chunk ];
+ *m_pos_sizepart = buf[ pos_chunk ];
// \n が来たらデータ部のサイズを取得
if( buf[ pos_chunk ] == '\n' ){
++pos_chunk;
- *( m_pos_sizepart ) = '\0';
- if( *( m_pos_sizepart -1 ) == '\r' ) *( m_pos_sizepart -1 ) = '\0'; // "\r\n"の場合
+ *m_pos_sizepart = '\0';
m_lng_leftdata = strtol( m_str_sizepart, NULL, 16 );
m_pos_sizepart = m_str_sizepart;
@@ -1419,7 +1120,14 @@ bool Loader::skip_chunk( char* buf, size_t& read_size )
// データを前に詰める
if( m_lng_leftdata ){
- for( ; m_lng_leftdata > 0 && pos_chunk < read_size; --m_lng_leftdata, ++pos_chunk );
+ if( m_lng_leftdata < read_size - pos_chunk ){
+ pos_chunk += m_lng_leftdata;
+ m_lng_leftdata = 0;
+ }
+ else{
+ m_lng_leftdata -= read_size - pos_chunk;
+ pos_chunk = read_size;
+ }
size_t buf_size_tmp = pos_chunk - pos_data_chunk_start;
if( buf_size != pos_data_chunk_start && buf_size_tmp ) memmove( buf + buf_size , buf + pos_data_chunk_start, buf_size_tmp );
buf_size += buf_size_tmp;
@@ -1429,8 +1137,8 @@ bool Loader::skip_chunk( char* buf, size_t& read_size )
if( m_lng_leftdata == 0 ) m_status_chunk = 2;
}
- // データ部→サイズ部切り替え中("\r"の前)
- if( m_status_chunk == 2 && pos_chunk != read_size ){
+ // データ部→サイズ部切り替え中( "\r" と "\n" の間でサーバからの入力が分かれる時がある)
+ if( m_status_chunk == 2 && pos_chunk < read_size ){
if( buf[ pos_chunk++ ] != '\r' ){
MISC::ERRMSG( "broken chunked data." );
@@ -1443,11 +1151,20 @@ bool Loader::skip_chunk( char* buf, size_t& read_size )
// データ部→サイズ部切り替え中("\n"の前: "\r" と "\n" の間でサーバからの入力が分かれる時がある)
if( m_status_chunk == 3 && pos_chunk != read_size ){
- if( buf[ pos_chunk++ ] != '\n' ){
+ unsigned char c = buf[ pos_chunk ];
+ if( c != '\r' && c != '\n' ){
MISC::ERRMSG( "broken chunked data." );
return false;
}
+ // \r\nが来たらサイズ部に戻る
+ if( c == '\r' && ++pos_chunk >= read_size ) break;
+ if( buf[ pos_chunk ] != '\n' ){
+ MISC::ERRMSG( "broken chunked data." );
+ return false;
+ }
+ ++pos_chunk;
+
#ifdef _DEBUG_CHUNKED
std::cout << "[[ skip_chunk : data chunk finished. ]]\n";
#endif
@@ -1458,7 +1175,6 @@ bool Loader::skip_chunk( char* buf, size_t& read_size )
if( pos_chunk == read_size ){
read_size = buf_size;
- buf[ read_size ] = '\0';
#ifdef _DEBUG_CHUNKED
std::cout << "[[ skip_chunk : output = " << read_size << " ]]\n\n";
@@ -1628,7 +1344,7 @@ bool Loader::unzip( char* buf, size_t& read_size )
#endif
// zlibの入力バッファに値セット
- if( m_zstream.avail_in + read_size > m_lng_buf_zlib_in ){ // オーバーフローのチェック
+ if( ( m_zstream.avail_in + read_size ) > m_lng_buf_zlib_in ){ // オーバーフローのチェック
MISC::ERRMSG( "buffer over flow at zstream_in : " + m_data.url );
return false;
@@ -1650,7 +1366,6 @@ bool Loader::unzip( char* buf, size_t& read_size )
if( ret == Z_OK || ret == Z_STREAM_END ){
byte_out = m_lng_buf_zlib_out - m_zstream.avail_out;
- m_buf_zlib_out[ byte_out ] = '\0';
m_data.size_data += byte_out;
#ifdef _DEBUG
@@ -1672,63 +1387,13 @@ bool Loader::unzip( char* buf, size_t& read_size )
} while ( byte_out );
// 入力バッファに使ってないデータが残っていたら前に移動
- if( m_zstream.avail_in ) memmove( m_buf_zlib_in, m_buf_zlib_in + ( read_size - m_zstream.avail_in ), m_zstream.avail_in );
+ if( m_zstream.avail_in ) memmove( m_buf_zlib_in, m_buf_zlib_in + ( m_lng_buf_zlib_in - m_zstream.avail_in ), m_zstream.avail_in );
return true;
}
-//
-// sent, recv待ち
-//
-bool Loader::wait_recv_send( const int fd, const bool recv )
-{
- if( !fd ) return true;
-
- // 同期している場合は何もしない
- if( !m_data.async ) return true;
-
- int count = 0;
- for(;;){
-
- errno = 0;
-
- int ret;
- fd_set fdset;
- FD_ZERO( &fdset );
- FD_SET( fd , &fdset );
-
- timeval timeout;
- memset( &timeout, 0, sizeof( timeval ) );
- timeout.tv_sec = 1;
-
- if( recv ) ret = select( fd+1 , &fdset , NULL , NULL , &timeout );
- else ret = select( fd+1 , NULL, &fdset , NULL , &timeout );
-
-#ifdef _DEBUG
- if( errno == EINTR && ret < 0 ) std::cout << "Loader::wait_recv_send : errno = EINTR " << errno << std::endl;
-#endif
- if( errno != EINTR && ret < 0 ){
-#ifdef _DEBUG
- std::cout << "Loader::wait_recv_send : errno = " << errno << std::endl;
-#endif
- MISC::ERRMSG( "select failed" );
- break;
- }
-
- if( errno != EINTR && FD_ISSET( fd, &fdset ) ) return true;
- if( m_stop ) break;
- if( ++count >= m_data.timeout ) break;
-#ifdef _DEBUG
- std::cout << "Loader::wait_recv_send ret = " << ret << " errno = " << errno << " timeout = " << count << std::endl;
-#endif
- }
-
- return false;
-}
-
-
//
// ローディング終了処理
//
diff --git a/src/jdlib/loader.h b/src/jdlib/loader.h
index 84ef2915..b198b615 100644
--- a/src/jdlib/loader.h
+++ b/src/jdlib/loader.h
@@ -16,14 +16,6 @@
#include <list>
#include <zlib.h>
-#ifdef _WIN32
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <netdb.h>
-#endif
-
// zlibが1.2よりバージョンが低いか判定する
#ifndef ZLIB_VERNUM
#define ZLIB_VERNUM 0x1000
@@ -44,7 +36,6 @@ namespace JDLIB
class Loader
{
LOADERDATA m_data;
- struct addrinfo* m_addrinfo;
bool m_stop; // = true にするとスレッド停止
bool m_loading;
@@ -101,10 +92,7 @@ namespace JDLIB
void clear();
void run_main();
- struct addrinfo* get_addrinfo( const std::string& hostname, const int port );
std::string create_msg_send();
- bool wait_recv_send( const int fd, const bool recv );
- bool send_connect( const int soc, std::string& errmsg );
// ローディング終了処理
void finish_loading();
diff --git a/src/jdlib/loaderdata.cpp b/src/jdlib/loaderdata.cpp
index 39474b33..707da9c8 100644
--- a/src/jdlib/loaderdata.cpp
+++ b/src/jdlib/loaderdata.cpp
@@ -31,11 +31,10 @@ void LOADERDATA::init()
path.clear();
port = 0;
use_ssl = false;
- async = true;
- use_ipv6 = CONFIG::get_use_ipv6();
str_post.clear();
+ protocol_proxy = 0;
host_proxy.clear();
port_proxy = 0;
basicauth_proxy.clear();
@@ -56,6 +55,8 @@ void LOADERDATA::init()
basicauth.clear();
size_buf = 0;
timeout = 0;
+ error.clear();
+ threadstatus = 0;
}
diff --git a/src/jdlib/loaderdata.h b/src/jdlib/loaderdata.h
index a4c77707..a1334558 100644
--- a/src/jdlib/loaderdata.h
+++ b/src/jdlib/loaderdata.h
@@ -26,22 +26,21 @@ namespace JDLIB
std::string protocol;
std::string host;
std::string path;
- long port;
+ int port;
bool use_ssl; // https
- bool async; // 非同期ソケット使用
- bool use_ipv6; // ipv6使用
std::string str_post;
+ int protocol_proxy;
std::string host_proxy;
- long port_proxy;
+ int port_proxy;
std::string basicauth_proxy; // proxy 認証
std::string agent;
std::string referer;
std::string ex_field; // 送信時にヘッダに追加するフィールド
std::string str_header;
- long code;
+ int code;
std::string str_code;
std::string date;
std::string modified;
@@ -52,7 +51,9 @@ namespace JDLIB
std::string contenttype;
std::string basicauth;
size_t size_buf;
- long timeout;
+ int timeout;
+ std::string error;
+ int threadstatus;
LOADERDATA();
diff --git a/src/jdlib/misccharcode.cpp b/src/jdlib/misccharcode.cpp
index 08863a16..bc88cb0b 100644
--- a/src/jdlib/misccharcode.cpp
+++ b/src/jdlib/misccharcode.cpp
@@ -3,6 +3,7 @@
//#define _DEBUG
#include "jddebug.h"
+#include "jdiconv.h"
#include "misccharcode.h"
#include <cstring>
@@ -11,6 +12,27 @@
// チェックする最大バイト数
#define CHECK_LIMIT 1024
+
+static char const * const encoding_string[] = { "ISO-8859-1", "ASCII", "EUCJP-MS", "ISO2022-JP", "MS932", "UTF-8" };
+
+const char* MISC::charcode_to_cstr( const CharCode charcode )
+{
+ CharCode code = charcode;
+ if( code > CHARCODE_UTF8 || code < CHARCODE_UNKNOWN ) code = CHARCODE_UNKNOWN;
+ return encoding_string[ code ];
+}
+
+CharCode MISC::charcode_from_cstr( const char* encoding )
+{
+ CharCode code = CHARCODE_UNKNOWN;
+
+ for( size_t i = sizeof( encoding_string ) / sizeof( char * ) - 1; i > 0; --i ){
+ if( strcmp( encoding_string[ i ], encoding ) == 0 ){ code = CharCode( i ); break; }
+ }
+ return code;
+}
+
+
/*--- 制御文字とASCII -----------------------------------------------*/
// [ 制御文字 ] 0x00〜0x1F 0x7F
@@ -40,14 +62,13 @@
// 2バイト目 0xA1〜0xFE
#define EUC_RANGE_MULTI( target ) ( (unsigned char)( target - 0xA1 ) < 0x5E )
//
-bool MISC::is_euc( const char* input, size_t& read_byte )
+bool MISC::is_eucjp( const char* input, const size_t length, size_t& read_byte )
{
- if( ! input ) return false;
+ if( ! input || ! length ) return false;
size_t byte = read_byte;
- const size_t input_length = strlen( input );
- while( byte < input_length && byte < CHECK_LIMIT )
+ while( byte < length && byte < CHECK_LIMIT )
{
// 制御文字かアスキー
if( CTRL_AND_ASCII_RANGE( input[ byte ] ) )
@@ -89,13 +110,11 @@ bool MISC::is_euc( const char* input, size_t& read_byte )
// エスケープシーケンスの開始文字 ESC(0x1B)
#define JIS_ESC_SEQ_START( target ) ( target == 0x1B )
//
-bool MISC::is_jis( const char* input, size_t& byte )
+bool MISC::is_jis( const char* input, const size_t length, size_t& byte )
{
- if( ! input ) return false;
+ if( ! input || ! length ) return false;
- const size_t input_length = strlen( input );
-
- while( byte < input_length && byte < CHECK_LIMIT )
+ while( byte < length && byte < CHECK_LIMIT )
{
// ESCが出現したか否かだけで判断
if( JIS_ESC_SEQ_START( input[ byte ] ) ) return true;
@@ -131,14 +150,13 @@ bool MISC::is_jis( const char* input, size_t& byte )
// 0x80〜0xFC
#define SJIS_RANGE_2_T( target ) ( (unsigned char)( target - 0x80 ) < 0x7D )
//
-bool MISC::is_sjis( const char* input, size_t& read_byte )
+bool MISC::is_sjis( const char* input, const size_t length, size_t& read_byte )
{
- if( ! input ) return false;
+ if( ! input || ! length ) return false;
size_t byte = read_byte;
- const size_t input_length = strlen( input );
- while( byte < input_length && byte < CHECK_LIMIT )
+ while( byte < length && byte < CHECK_LIMIT )
{
// 制御文字かアスキー
if( CTRL_AND_ASCII_RANGE( input[ byte ] ) )
@@ -171,32 +189,33 @@ bool MISC::is_sjis( const char* input, size_t& read_byte )
//
// 0xC0・0xC1はセキュリティ上の問題で使用が禁止されている
//
-// [ 1バイト目の範囲 ] 0xC2〜0xFD [ RFC2279(破棄) ]
-// [ 1バイト目の範囲 ] 0xC2〜0xF4 [ RFC6329 ]
+// [ 1バイト目の範囲 ] 0xC2~0xFD [ RFC2279(破棄) ]
+// [ 1バイト目の範囲 ] 0xC2~0xF4 [ RFC6329 ]
#define UTF_RANGE_1( target ) ( (unsigned char)( target - 0xC2 ) < 0x33 )
//
-// [ 1バイト目 (2バイト文字) ] 先頭2ビットが1
-#define UTF_FLAG_2( target ) ( ( target & 0xC0 ) == 0xC0 )
+// [ 2バイト目以降 ] 0x80~0xBF 先頭ビットが10
+#define UTF_RANGE_MULTI_BYTE( target ) ( ( target & 0xC0 ) == 0x80 )
//
-// [ 1バイト目 (3バイト文字) ] 先頭3ビットが1
-#define UTF_FLAG_3( target ) ( ( target & 0xE0 ) == 0xE0 )
+// [ 1バイト目 (2バイト文字) ] 先頭ビットが110
+//#define UTF_FLAG_2( target ) ( ( target & 0xE0 ) == 0xC0 )
+// [ 1バイト目 (2バイト文字) ] 0xC2~0xDF
+#define UTF_FLAG_2( target ) ( (unsigned char)( target - 0xC2 ) < 0x1E )
//
-// [ 1バイト目 (4バイト文字) ] 先頭4ビットが1
-#define UTF_FLAG_4( target ) ( ( target & 0xF0 ) == 0xF0 )
+// [ 1バイト目 (3バイト文字) ] 先頭ビットが1110
+#define UTF_FLAG_3( target ) ( ( target & 0xF0 ) == 0xE0 )
//
-// [ 2バイト目以降 ] 0x80〜0xBF
-#define UTF_RANGE_MULTI_BYTE( target ) ( (unsigned char)( target - 0x80 ) < 0x40 )
+// [ 1バイト目 (4バイト文字) ] 先頭ビットが11110
+#define UTF_FLAG_4( target ) ( ( target & 0xF8 ) == 0xF0 )
//
-bool MISC::is_utf( const char* input, size_t& read_byte )
+bool MISC::is_utf8( const char* input, const size_t length, size_t& read_byte )
{
- if( ! input ) return false;
+ if( ! input || ! length ) return false;
bool valid = true;
size_t byte = read_byte;
- const size_t input_length = strlen( input );
- while( byte < input_length && byte < CHECK_LIMIT )
+ while( byte < length && byte < CHECK_LIMIT )
{
// 制御文字かアスキー
if( CTRL_AND_ASCII_RANGE( input[ byte ] ) )
@@ -246,25 +265,237 @@ bool MISC::is_utf( const char* input, size_t& read_byte )
// 各コードの判定でtrueの間は文字数分繰り返されるので
// 速度の求められる繰り返し処理などで使わない事
//
-int MISC::judge_char_code( const std::string& str )
+CharCode MISC::judge_char_code( const std::string& str )
{
- int code = CHARCODE_UNKNOWN;
+ CharCode code = CHARCODE_UNKNOWN;
if( str.empty() ) return code;
size_t read_byte = 0;
// JISの判定
- if( is_jis( str.c_str(), read_byte ) ) code = CHARCODE_JIS;
+ if( is_jis( str.c_str(), str.length(), read_byte ) ) code = CHARCODE_JIS;
// JISの判定で最後まで進んでいたら制御文字かアスキー
else if( read_byte == str.length() ) code = CHARCODE_ASCII;
// UTF-8の範囲
- else if( is_utf( str.c_str(), read_byte ) ) code = CHARCODE_UTF;
+ else if( is_utf8( str.c_str(), str.length(), read_byte ) ) code = CHARCODE_UTF8;
// EUC-JPの範囲
- else if( is_euc( str.c_str(), read_byte ) ) code = CHARCODE_EUC_JP;
+ else if( is_eucjp( str.c_str(), str.length(), read_byte ) ) code = CHARCODE_EUCJP;
// Shift_JISの範囲
- else if( is_sjis( str.c_str(), read_byte ) ) code = CHARCODE_SJIS;
+ else if( is_sjis( str.c_str(), str.length(), read_byte ) ) code = CHARCODE_SJIS;
return code;
}
+
+//
+// utf-8 byte数
+//
+// 入力 : utfstr 入力文字 (UTF-8)
+// 戻り値 : byte 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を返す
+//
+int MISC::utf8bytes( const char* utfstr )
+{
+ int byte = 0;
+
+ if( utfstr && *utfstr != '\0' ){
+ char ch = ( unsigned char ) *utfstr;
+ if( ch >= 0 ) byte = 1;
+ else if( UTF_FLAG_3( ch ) ) byte = 3;
+ else if( UTF_FLAG_4( ch ) ) byte = 4;
+ else if( UTF_FLAG_2( ch ) ) byte = 2;
+#ifdef _DEBUG
+ else { // 不正なUTF8
+ std::cout << "MISC::utf8bytes : invalid 1st byte: char = " << (unsigned int) ch << std::endl;
+ }
+#endif
+ }
+
+ for( int i = 1; i < byte; ++i ){
+ if( ! UTF_RANGE_MULTI_BYTE( utfstr[ i ] ) ){
+#ifdef _DEBUG
+ // 不正なUTF8
+ std::cout << "MISC::utf8bytes : invalid code: char = " << (unsigned int) utfstr[ 0 ];
+ std::cout << ", " << (unsigned int) utfstr[ 1 ];
+ if( byte > 2 ) std::cout << ", " << (unsigned int) utfstr[ 2 ];
+ if( byte > 3 ) std::cout << ", " << (unsigned int) utfstr[ 3 ];
+ std::cout << std::endl;
+#endif
+ byte = 0;
+ break;
+ }
+ }
+
+ return byte;
+}
+
+
+//
+// utf-8 -> code point 変換
+//
+// 入力 : utfstr 入力文字 (UTF-8)
+// 出力 : byte 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す
+// 戻り値 : code point
+//
+int MISC::utf8tocp( const char* utfstr, int& byte )
+{
+ int code = 0;
+ byte = utf8bytes( utfstr );
+
+ switch( byte ){
+ case 1:
+ code = utfstr[ 0 ];
+ break;
+
+ case 2:
+ code = utfstr[ 0 ] & 0x1f;
+ code = ( code << 6 ) + ( utfstr[ 1 ] & 0x3f );
+ break;
+
+ case 3:
+ code = utfstr[ 0 ] & 0x0f;
+ code = ( code << 6 ) + ( utfstr[ 1 ] & 0x3f );
+ code = ( code << 6 ) + ( utfstr[ 2 ] & 0x3f );
+ break;
+
+ case 4:
+ code = utfstr[ 0 ] & 0x07;
+ code = ( code << 6 ) + ( utfstr[ 1 ] & 0x3f );
+ code = ( code << 6 ) + ( utfstr[ 2 ] & 0x3f );
+ code = ( code << 6 ) + ( utfstr[ 3 ] & 0x3f );
+ break;
+
+ default:
+ break;
+ }
+
+ return code;
+}
+
+
+//
+// ucs2 -> utf8 変換
+//
+// 出力 : utfstr 変換後の文字
+// 戻り値 : バイト数
+//
+int MISC::cptoutf8( const int code, char* utfstr )
+{
+ int byte = 0;
+
+ if( code <= 0x7f ){ // ascii
+ byte = 1;
+ utfstr[ 0 ] = code;
+ }
+
+ else if( code <= 0x07ff ){
+ byte = 2;
+ utfstr[ 0 ] = ( 0xc0 ) + ( code >> 6 );
+ utfstr[ 1 ] = ( 0x80 ) + ( code & 0x3f );
+ }
+
+ else if( code <= 0xffff){
+ byte = 3;
+ utfstr[ 0 ] = ( 0xe0 ) + ( code >> 12 );
+ utfstr[ 1 ] = ( 0x80 ) + ( ( code >>6 ) & 0x3f );
+ utfstr[ 2 ] = ( 0x80 ) + ( code & 0x3f );
+ }
+
+ else if( code <= 0x1fffff ){
+ byte = 4;
+ utfstr[ 0 ] = ( 0xf0 ) + ( code >> 18 );
+ utfstr[ 1 ] = ( 0x80 ) + ( ( code >>12 ) & 0x3f );
+ utfstr[ 2 ] = ( 0x80 ) + ( ( code >>6 ) & 0x3f );
+ utfstr[ 3 ] = ( 0x80 ) + ( code & 0x3f );
+ }
+
+#ifdef _DEBUG
+ else{
+ std::cout << "MISC::cptoutf8 : invalid code = " << code << std::endl;
+ }
+#endif
+
+ utfstr[ byte ] = 0;
+ return byte;
+}
+
+
+//
+// ucs の種類
+//
+int MISC::get_ucstype( const int code )
+{
+ if( code >= 0x0000 && code <= 0x007f ) return UCSTYPE_BASIC_LATIN;
+ if( code >= 0x3040 && code <= 0x309f ) return UCSTYPE_HIRA;
+ if( code >= 0x30a0 && code <= 0x30ff ) return UCSTYPE_KATA;
+
+ return UCSTYPE_OTHER;
+}
+
+//
+// WAVEDASHなどのWindows系UTF-8文字をUnix系文字と相互変換
+//
+std::string MISC::utf8_fix_wavedash( const std::string& str, const int mode )
+{
+ // WAVE DASH 問題
+ const size_t size = 4;
+ static const unsigned char Win[size][4] = {
+ { 0xef, 0xbd, 0x9e, '\0' }, // FULLWIDTH TILDE (U+FF5E)
+ { 0xe2, 0x80, 0x95, '\0' }, // HORIZONTAL BAR (U+2015)
+ { 0xe2, 0x88, 0xa5, '\0' }, // PARALLEL TO (U+2225)
+ { 0xef, 0xbc, 0x8d, '\0' } // FULLWIDTH HYPHEN-MINUS (U+FF0D)
+ };
+ static const unsigned char Unix[size][4] = {
+ { 0xe3, 0x80, 0x9c, '\0' }, // WAVE DASH (U+301C)
+ { 0xe2, 0x80, 0x94, '\0' }, // EM DASH(U+2014)
+ { 0xe2, 0x80, 0x96, '\0' }, // DOUBLE VERTICAL LINE (U+2016)
+ { 0xe2, 0x88, 0x92, '\0' } // MINUS SIGN (U+2212)
+ };
+
+ std::string ret(str);
+
+ if( mode == WINtoUNIX ){
+
+ for( size_t i = 0; i < ret.length(); i++ ) {
+ for( size_t s = 0; s < size; s++ ) {
+ if( ret[ i ] != (char)Win[ s ][ 0 ] || ret[ i+1 ] != (char)Win[ s ][ 1 ] || ret[ i+2 ] != (char)Win[ s ][ 2 ] )
+ continue;
+ for( size_t t = 0; t < 3; t++ )
+ ret[ i+t ] = (char)Unix[ s ][ t ];
+ i += 2;
+ break;
+ }
+ }
+
+ }else{
+
+ for( size_t i = 0; i < ret.length(); i++ ) {
+ for( size_t s = 0; s < size; s++ ) {
+ if( ret[ i ] != (char)Unix[ s ][ 0 ] || ret[ i+1 ] != (char)Unix[ s ][ 1 ] || ret[ i+2 ] != (char)Unix[ s ][ 2 ] )
+ continue;
+ for( size_t t = 0; t < 3; t++ )
+ ret[ i+t ] = (char)Win[ s ][ t ];
+ i += 2;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+//
+// 文字コードを from から to に変換
+//
+// 遅いので連続的な処理が必要な時は使わないこと
+//
+std::string MISC::Iconv( const std::string& str, const CharCode from, const CharCode to )
+{
+ if( from == to ) return str;
+
+ JDLIB::Iconv icv( from, to );
+ int byte_out;
+
+ return icv.convert( str.c_str(), str.length(), byte_out );
+}
diff --git a/src/jdlib/misccharcode.h b/src/jdlib/misccharcode.h
index ec953070..05f296f7 100644
--- a/src/jdlib/misccharcode.h
+++ b/src/jdlib/misccharcode.h
@@ -5,25 +5,64 @@
#ifndef _MISCCHARCODE_H
#define _MISCCHARCODE_H
+#include "charcode.h"
+
#include <string>
+
namespace MISC
{
- enum CodeSet
+ // get_ucstype()の戻り値
+ enum
{
- CHARCODE_UNKNOWN = -1,
- CHARCODE_ASCII = 0,
- CHARCODE_EUC_JP,
- CHARCODE_JIS,
- CHARCODE_SJIS,
- CHARCODE_UTF
+ UCSTYPE_BASIC_LATIN = 0,
+ UCSTYPE_HIRA,
+ UCSTYPE_KATA,
+
+ UCSTYPE_OTHER
};
- bool is_euc( const char* input, size_t& read_byte );
- bool is_jis( const char* input, size_t& read_byte );
- bool is_sjis( const char* input, size_t& read_byte );
- bool is_utf( const char* input, size_t& read_byte );
- int judge_char_code( const std::string& str );
+
+ // utf8_fix_wavedash のモード
+ enum
+ {
+ UNIXtoWIN = 0,
+ WINtoUNIX
+ };
+
+
+ const char* charcode_to_cstr( const CharCode charcode );
+ CharCode charcode_from_cstr( const char* encoding );
+ bool is_eucjp( const char* input, const size_t length, size_t& read_byte );
+ bool is_jis( const char* input, const size_t length, size_t& read_byte );
+ bool is_sjis( const char* input, const size_t length, size_t& read_byte );
+ bool is_utf8( const char* input, const size_t length, size_t& read_byte );
+ CharCode judge_char_code( const std::string& str );
+
+ // utf-8 -> code point 変換
+ // 入力 : utfstr 入力文字 (UTF-8)
+ // 出力 : byte 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す
+ // 戻り値 : unicode code point
+ int utf8tocp( const char* utfstr, int& byte );
+
+ // utf-8文字のbyte数
+ int utf8bytes( const char* utfstr );
+
+ // ucs の種類
+ int get_ucstype( const int code );
+
+ // code point -> utf8 変換
+ // 出力 : utfstr 変換後の文字
+ // 戻り値 : バイト数
+ int cptoutf8( const int code, char* utfstr );
+
+ // WAVEDASHなどのWindows系UTF-8文字をUnix系文字と相互変換
+ std::string utf8_fix_wavedash( const std::string& str, const int mode );
+
+ // 文字コードを from から to に変換
+ // 遅いので連続的な処理が必要な時は使わないこと
+ std::string Iconv( const std::string& str, const CharCode from, const CharCode to );
+
}
#endif
diff --git a/src/jdlib/miscgtk.cpp b/src/jdlib/miscgtk.cpp
index edfed527..984879a0 100644
--- a/src/jdlib/miscgtk.cpp
+++ b/src/jdlib/miscgtk.cpp
@@ -4,6 +4,7 @@
#include "jddebug.h"
#include "miscgtk.h"
+#include "miscutil.h"
#include "imgloader.h"
@@ -13,6 +14,195 @@ enum
};
+static struct color_map {
+ const char *name;
+ const char *rgb;
+} const color_names[] = {
+ // basic html colors
+ { "red", "#ff0000" },
+ { "fuchsia", "#ff00ff" },
+ { "purple", "#800080" },
+ { "maroon", "#800000" },
+ { "yellow", "#ffff00" },
+ { "lime", "#00ff00" },
+ { "green", "#008000" },
+ { "olive", "#808000" },
+ { "blue", "#0000ff" },
+ { "aqua", "#00ffff" },
+ { "teal", "#008080" },
+ { "navy", "#000080" },
+ { "white", "#ffffff" },
+ { "silver", "#c0c0c0" },
+ { "gray", "#808080" },
+ { "black", "#000000" },
+ { "orange", "#ffa500" }, // since CSS2.1
+
+ // other X11 colors
+
+ //Red color names
+ { "indianred", "#CD5C5C" },
+ { "lightcoral", "#F08080" },
+ { "salmon", "#FA8072" },
+ { "darksalmon", "#E9967A" },
+ { "lightsalmon", "#FFA07A" },
+ { "crimson", "#DC143C" },
+// { "red", "#FF0000" },
+ { "firebrick", "#B22222" },
+ { "darkred", "#8B0000" },
+
+ //Pink color names
+ { "pink", "#FFC0CB" },
+ { "lightpink", "#FFB6C1" },
+ { "hotpink", "#FF69B4" },
+ { "deeppink", "#FF1493" },
+ { "mediumvioletred","#C71585" },
+ { "palevioletred", "#DB7093" },
+
+ //Orange color names
+ { "lightsalmon", "#FFA07A" },
+ { "coral", "#FF7F50" },
+ { "tomato", "#FF6347" },
+ { "orangered", "#FF4500" },
+ { "darkorange", "#FF8C00" },
+// { "orange", "#FFA500" },
+
+ //Yellow color names
+ { "gold", "#FFD700" },
+// { "yellow", "#FFFF00" },
+ { "lightyellow", "#FFFFE0" },
+ { "lemonchiffon", "#FFFACD" },
+ { "lightgoldenrodyellow", "#FAFAD2" },
+ { "papayawhip", "#FFEFD5" },
+ { "moccasin", "#FFE4B5" },
+ { "peachpuff", "#FFDAB9" },
+ { "palegoldenrod", "#EEE8AA" },
+ { "khaki", "#F0E68C" },
+ { "darkkhaki", "#BDB76B" },
+
+ //Purple color names
+ { "lavender", "#E6E6FA" },
+ { "thistle", "#D8BFD8" },
+ { "plum", "#DDA0DD" },
+ { "violet", "#EE82EE" },
+ { "orchid", "#DA70D6" },
+// { "fuchsia", "#FF00FF" },
+ { "magenta", "#FF00FF" },
+ { "mediumorchid", "#BA55D3" },
+ { "mediumpurple", "#9370DB" },
+ { "blueviolet", "#8A2BE2" },
+ { "darkviolet", "#9400D3" },
+ { "darkorchid", "#9932CC" },
+ { "darkmagenta", "#8B008B" },
+// { "purple", "#800080" },
+ { "indigo", "#4B0082" },
+ { "slateblue", "#6A5ACD" },
+ { "darkslateblue", "#483D8B" },
+ { "mediumslateblue","#7B68EE" },
+
+ //Green color names
+ { "greenyellow", "#ADFF2F" },
+ { "chartreuse", "#7FFF00" },
+ { "lawngreen", "#7CFC00" },
+// { "lime", "#00FF00" },
+ { "limegreen", "#32CD32" },
+ { "palegreen", "#98FB98" },
+ { "lightgreen", "#90EE90" },
+ { "mediumspringgreen", "#00FA9A" },
+ { "springgreen", "#00FF7F" },
+ { "mediumseagreen", "#3CB371" },
+ { "seagreen", "#2E8B57" },
+ { "forestgreen", "#228B22" },
+// { "green", "#008000" },
+ { "darkgreen", "#006400" },
+ { "yellowgreen", "#9ACD32" },
+ { "olivedrab", "#6B8E23" },
+// { "olive", "#808000" },
+ { "darkolivegreen", "#556B2F" },
+ { "mediumaquamarine", "#66CDAA" },
+ { "darkseagreen", "#8FBC8F" },
+ { "lightseagreen", "#20B2AA" },
+ { "darkcyan", "#008B8B" },
+// { "teal", "#008080" },
+
+ //Blue color names
+// { "aqua", "#00FFFF" },
+ { "cyan", "#00FFFF" },
+ { "lightcyan", "#E0FFFF" },
+ { "paleturquoise", "#AFEEEE" },
+ { "aquamarine", "#7FFFD4" },
+ { "turquoise", "#40E0D0" },
+ { "mediumturquoise","#48D1CC" },
+ { "darkturquoise", "#00CED1" },
+ { "cadetblue", "#5F9EA0" },
+ { "steelblue", "#4682B4" },
+ { "lightsteelblue", "#B0C4DE" },
+ { "powderblue", "#B0E0E6" },
+ { "lightblue", "#ADD8E6" },
+ { "skyblue", "#87CEEB" },
+ { "lightskyblue", "#87CEFA" },
+ { "deepskyblue", "#00BFFF" },
+ { "dodgerblue", "#1E90FF" },
+ { "cornflowerblue", "#6495ED" },
+ { "mediumslateblue","#7B68EE" },
+ { "royalblue", "#4169E1" },
+// { "blue", "#0000FF" },
+ { "mediumblue", "#0000CD" },
+ { "darkblue", "#00008B" },
+// { "navy", "#000080" },
+ { "midnightblue", "#191970" },
+
+ //Brown color names
+ { "cornsilk", "#FFF8DC" },
+ { "blanchedalmond", "#FFEBCD" },
+ { "bisque", "#FFE4C4" },
+ { "navajowhite", "#FFDEAD" },
+ { "wheat", "#F5DEB3" },
+ { "burlywood", "#DEB887" },
+ { "tan", "#D2B48C" },
+ { "rosybrown", "#BC8F8F" },
+ { "sandybrown", "#F4A460" },
+ { "goldenrod", "#DAA520" },
+ { "darkgoldenrod", "#B8860B" },
+ { "peru", "#CD853F" },
+ { "chocolate", "#D2691E" },
+ { "saddlebrown", "#8B4513" },
+ { "sienna", "#A0522D" },
+ { "brown", "#A52A2A" },
+// { "maroon", "#800000" },
+
+ //White color names
+// { "white", "#FFFFFF" },
+ { "snow", "#FFFAFA" },
+ { "honeydew", "#F0FFF0" },
+ { "mintcream", "#F5FFFA" },
+ { "azure", "#F0FFFF" },
+ { "aliceblue", "#F0F8FF" },
+ { "ghostwhite", "#F8F8FF" },
+ { "whitesmoke", "#F5F5F5" },
+ { "seashell", "#FFF5EE" },
+ { "beige", "#F5F5DC" },
+ { "oldlace", "#FDF5E6" },
+ { "floralwhite", "#FFFAF0" },
+ { "ivory", "#FFFFF0" },
+ { "antiquewhite", "#FAEBD7" },
+ { "linen", "#FAF0E6" },
+ { "lavenderblush", "#FFF0F5" },
+ { "mistyrose", "#FFE4E1" },
+
+ //Grey color names
+ { "gainsboro", "#DCDCDC" },
+ { "lightgrey", "#D3D3D3" },
+// { "silver", "#C0C0C0" },
+ { "darkgray", "#A9A9A9" },
+// { "gray", "#808080" },
+ { "dimgray", "#696969" },
+ { "lightslategray", "#778899" },
+ { "slategray", "#708090" },
+ { "darkslategray", "#2F4F4F" },
+// { "black", "#000000" },
+};
+
+
// Gdk::Color -> 16進数表記の文字列
std::string MISC::color_to_str( const Gdk::Color& color )
{
@@ -57,37 +247,28 @@ std::string MISC::color_to_str( const Gdk::RGBA& rgba )
// htmlカラー (#ffffffなど) -> 16進数表記の文字列
std::string MISC::htmlcolor_to_str( const std::string& _htmlcolor )
{
- std::string htmlcolor = _htmlcolor;
+ std::string htmlcolor = MISC::tolower_str( _htmlcolor );
int rgb[ 3 ];
- if( htmlcolor == "red" ) htmlcolor = "#ff0000";
- else if( htmlcolor == "fuchsia" ) htmlcolor = "#ff00ff";
- else if( htmlcolor == "purple" ) htmlcolor = "#800080";
- else if( htmlcolor == "maroon" ) htmlcolor = "#800000";
- else if( htmlcolor == "yellow" ) htmlcolor = "#ffff00";
- else if( htmlcolor == "lime" ) htmlcolor = "#00ff00";
- else if( htmlcolor == "green" ) htmlcolor = "#008000";
- else if( htmlcolor == "olive" ) htmlcolor = "#808000";
- else if( htmlcolor == "blue" ) htmlcolor = "#0000ff";
- else if( htmlcolor == "aqua" ) htmlcolor = "#00ffff";
- else if( htmlcolor == "teal" ) htmlcolor = "#008080";
- else if( htmlcolor == "navy" ) htmlcolor = "#000080";
- else if( htmlcolor == "white" ) htmlcolor = "#ffffff";
- else if( htmlcolor == "silver" ) htmlcolor = "#c0c0c0";
- else if( htmlcolor == "gray" ) htmlcolor = "#808080";
- else if( htmlcolor == "black" ) htmlcolor = "#000000";
+ if( htmlcolor[ 0 ] != '#' ){
+ const color_map* col = color_names;
+ const int lng_ary = sizeof( color_names ) / sizeof( color_map );
+ int i;
+ for( i = 0; i < lng_ary; ++i, ++col ){
+ if( htmlcolor[0] == *( col->name ) && htmlcolor == col->name ) break;
+ }
+ if( i >= lng_ary ) return std::string();
+ htmlcolor = col->rgb;
+ }
- int offset = 0;
- if( htmlcolor.find( "#" ) == 0 ) offset = 1;
+ int n = ( htmlcolor.length() == 4 ) ? 1 : 2;
- std::string tmpstr = htmlcolor.substr( offset, 2 );
- rgb[ 0 ] = strtol( std::string( "0x" + tmpstr + tmpstr ).c_str(), NULL, 16 );
-
- tmpstr = htmlcolor.substr( 2 + offset, 2 );
- rgb[ 1 ] = strtol( std::string( "0x" + tmpstr + tmpstr ).c_str(), NULL, 16 );
-
- tmpstr = htmlcolor.substr( 4 + offset, 2 );
- rgb[ 2 ] = strtol( std::string( "0x" + tmpstr + tmpstr ).c_str(), NULL, 16 );
+ for( int i = 0; i < 3; ++i ){
+ const int offset = 1;
+ std::string tmpstr = htmlcolor.substr( offset + ( i * n ), n );
+ for( int j = 0; j < ( 3 - n ); ++j ) tmpstr += tmpstr;
+ rgb[ i ] = strtol( std::string( "0x" + tmpstr ).c_str(), NULL, 16 );
+ }
#ifdef _DEBUG
std::cout << "MISC::htmlcolor_to_gdkcolor color = " << htmlcolor
@@ -148,6 +329,13 @@ std::string MISC::get_entry_color_text()
auto rgba = entry.get_style_context()->get_color( Gtk::STATE_FLAG_NORMAL );
return color_to_str( rgba );
#else
+ Gtk::Window win( Gtk::WINDOW_POPUP );
+
+ win.add( entry );
+ win.move( 0,0 );
+ win.resize( 1,1 );
+ win.show_all();
+
return color_to_str( entry.get_style()->get_text( Gtk::STATE_NORMAL ) );
#endif
}
@@ -169,6 +357,13 @@ std::string MISC::get_entry_color_base()
}
return color_to_str( rgba );
#else
+ Gtk::Window win( Gtk::WINDOW_POPUP );
+
+ win.add( entry );
+ win.move( 0,0 );
+ win.resize( 1,1 );
+ win.show_all();
+
return color_to_str( entry.get_style()->get_base( Gtk::STATE_NORMAL ) );
#endif
}
diff --git a/src/jdlib/misctrip.cpp b/src/jdlib/misctrip.cpp
index f08f89cb..caad0672 100644
--- a/src/jdlib/misctrip.cpp
+++ b/src/jdlib/misctrip.cpp
@@ -3,27 +3,40 @@
//#define _DEBUG
#include "jddebug.h"
+#include "misccharcode.h"
#include "misctrip.h"
#include "miscutil.h"
#include <sstream>
#include <cstring>
#include <ctype.h>
-#include <unistd.h> // crypt
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#ifdef USE_OPENSSL
-#include <array>
-#include <openssl/sha.h>
-#else // defined USE_GNUTLS
-#include <gcrypt.h>
+#if defined (USE_NSS)
+# include <nss/pk11pub.h>
+# include <nss/nss.h>
+#elif defined (USE_GNUTLS)
+# include <gnutls/gnutls.h>
+# include <gnutls/crypto.h>
+#elif defined (USE_OPENSSL)
+# include <openssl/sha.h>
+# include <openssl/hmac.h>
+#else // libgcrypt
+# include <gcrypt.h>
#endif
-#ifdef HAVE_CRYPT_H
-#include <crypt.h>
+// for crypt
+#if defined (USE_OPENSSL)
+# include <openssl/des.h>
+#elif defined (HAVE_CRYPT_H)
+# include <crypt.h>
+#elif defined (_WIN32)
+# include <encrypt.h>
+#else
+# include <unistd.h>
#endif
@@ -52,21 +65,25 @@ std::string create_sha1( const std::string& key )
{
if( key.empty() ) return std::string();
-#ifdef USE_OPENSSL
+ std::array< unsigned char, 20 > digest; // SHA_DIGEST_LENGTH
- constexpr const unsigned int digest_length = SHA_DIGEST_LENGTH;
+#if defined USE_NSS
+ PK11Context* context;
- std::array< unsigned char, digest_length > digest;
+ if( ( context = PK11_CreateDigestContext( SEC_OID_SHA1 ) ) ){
+ unsigned int len = digest.size();
+ PK11_DigestOp( context, (const unsigned char*)key.c_str(), key.length() );
+ PK11_DigestFinal( context, digest.data(), &len, len );
+ PK11_DestroyContext( context, PR_TRUE );
+ }
- // unsigned char *SHA1( const unsigned char *, size_t, unsigned char * );
+#elif defined USE_OPENSSL
SHA1( (const unsigned char *)key.c_str(), key.length(), digest.data() );
-#else // defined USE_GNUTLS
-
- const unsigned int digest_length = gcry_md_get_algo_dlen( GCRY_MD_SHA1 );
-
- std::vector< unsigned char > digest( digest_length );
+#elif defined USE_GNUTLS
+ gnutls_hash_fast( GNUTLS_DIG_SHA1, key.c_str(), key.length(), digest.data() );
+#else // libgcrypt
gcry_md_hash_buffer( GCRY_MD_SHA1, digest.data(), key.c_str(), key.length() );
#endif
@@ -77,18 +94,17 @@ std::string create_sha1( const std::string& key )
std::cout << "create_sha1 : SHA1 = ";
#endif
- unsigned int n;
- for( n = 0; n < digest_length; ++n )
+ for( const unsigned char c : digest )
{
- sha1 << digest[n];
+ sha1 << c;
#ifdef _DEBUG
- std::cout << std::hex << (unsigned int)digest[n] << std::dec;
+ std::cout << std::hex << c << std::dec;
#endif
}
#ifdef _DEBUG
- std::cout << std::endl;
+ std::cout << std::dec << std::endl;
#endif
return sha1.str();
@@ -153,7 +169,16 @@ std::string create_trip_newtype( const std::string& key )
strncat( salt, "..", 2 );
// crypt (key は先頭8文字しか使われない)
+#ifdef USE_OPENSSL
+ char ret[14];
+ const char *crypted = DES_fcrypt( key_binary, salt, ret );
+#elif defined( _GNU_SOURCE )
+ struct crypt_data crydat;
+ crydat.initialized = 0;
+ const char *crypted = crypt_r( key_binary, salt, &crydat );
+#else
const char *crypted = crypt( key_binary, salt );
+#endif
// 末尾から10文字(cryptの戻り値はNULLでなければ必ず13文字)
if( crypted ) trip = std::string( crypted + 3 );
@@ -226,7 +251,16 @@ std::string create_trip_conventional( const std::string& key )
salt.append( "H." );
// crypt (key は先頭8文字しか使われない)
+#ifdef USE_OPENSSL
+ char ret[14];
+ const char *crypted = DES_fcrypt( key.c_str(), salt.c_str(), ret );
+#elif defined( _GNU_SOURCE )
+ struct crypt_data crydat;
+ crydat.initialized = 0;
+ const char *crypted = crypt_r( key.c_str(), salt.c_str(), &crydat );
+#else
const char *crypted = crypt( key.c_str(), salt.c_str() );
+#endif
std::string trip;
@@ -244,12 +278,12 @@ std::string create_trip_conventional( const std::string& key )
// param2: 書き込む掲示板の文字コード
// return: トリップ文字列
/*--------------------------------------------------------------------*/
-std::string MISC::get_trip( const std::string& str, const std::string& charset )
+std::string MISC::get_trip( const std::string& str, const CharCode charcode )
{
if( str.empty() ) return std::string();
- // str の文字コードを UTF-8 から charset に変更して key に代入する
- std::string key = MISC::Iconv( str, "UTF-8", charset );
+ // str の文字コードを UTF-8 から変更して key に代入する
+ std::string key = MISC::Iconv( str, CHARCODE_UTF8, charcode );
std::string trip;
@@ -270,3 +304,21 @@ std::string MISC::get_trip( const std::string& str, const std::string& charset )
return trip;
}
+
+
+//
+// FNV Hash Algorithm
+//
+uint32_t MISC::fnv_hash( const char *key, size_t length )
+{
+ const uint32_t OFFSET = 2166136261U;
+ const uint32_t PRIME = 16777619U;
+
+ uint32_t hash = OFFSET;
+ uint8_t *bytes = (uint8_t*)key;
+ for(size_t i = 0 ; i < length ; ++i) {
+ hash = (PRIME * hash) ^ bytes[i];
+ }
+
+ return hash;
+}
diff --git a/src/jdlib/misctrip.h b/src/jdlib/misctrip.h
index a4fbea25..883e2e8d 100644
--- a/src/jdlib/misctrip.h
+++ b/src/jdlib/misctrip.h
@@ -5,12 +5,16 @@
#ifndef _MISCTRIP_H
#define _MISCTRIP_H
+#include "charcode.h"
+
#include <string>
namespace MISC
{
// トリップを取得 (SHA1等の新方式対応)
- std::string get_trip( const std::string& str, const std::string& charset );
+ std::string get_trip( const std::string& str, const CharCode charcode );
+ // FNV Hash
+ uint32_t fnv_hash( const char *key, size_t length );
}
#endif
diff --git a/src/jdlib/miscutil.cpp b/src/jdlib/miscutil.cpp
index 06f8f52b..62044d55 100644
--- a/src/jdlib/miscutil.cpp
+++ b/src/jdlib/miscutil.cpp
@@ -3,6 +3,7 @@
//#define _DEBUG
#include "jddebug.h"
+#include "misccharcode.h"
#include "miscutil.h"
#include "miscmsg.h"
#include "jdiconv.h"
@@ -12,6 +13,8 @@
#include "dbtree/spchar_decoder.h"
#include "dbtree/node.h"
+#include "cssmanager.h"
+
#include <sstream>
#include <cstring>
#include <cstdio>
@@ -25,7 +28,7 @@ std::list< std::string > MISC::get_lines( const std::string& str ){
std::list< std::string > lines;
size_t i = 0, i2 = 0, r = 0;
- while ( ( i2 = str.find( "\n", i ) ) != std::string::npos ){
+ while ( ( i2 = str.find_first_of( '\n', i ) ) != std::string::npos ){
r = 0;
if( (i2 >= 1) && (str[ i2 - 1 ] == '\r') ) r = 1;
if( i2 - i > 0 ){
@@ -111,8 +114,8 @@ std::list< std::string > MISC::get_elisp_lists( const std::string& str )
//
std::list< std::string > MISC::split_line( const std::string& str )
{
- std::string str_space = " ";
- size_t lng_space = str_space.length();
+ const char* str_space = "\xE3\x80\x80"; // " " 空白
+ const size_t lng_space = 3;
bool dquote;
std::list< std::string > list_str;
@@ -129,7 +132,7 @@ std::list< std::string > MISC::split_line( const std::string& str )
// 全角
else if( str[ i ] == str_space[ 0 ] &&
str[ i +1 ] == str_space[ 1 ] &&
- ( lng_space == 2 || str[ i +2 ] == str_space[ 2 ] ) ) i += lng_space;
+ str[ i +2 ] == str_space[ 2 ] ) i += lng_space;
else break;
}
@@ -157,7 +160,7 @@ std::list< std::string > MISC::split_line( const std::string& str )
// 全角
else if( str[ i2 ] == str_space[ 0 ] &&
str[ i2 +1 ] == str_space[ 1 ] &&
- ( lng_space == 2 || str[ i2 +2 ] == str_space[ 2 ] ) ){
+ str[ i2 +2 ] == str_space[ 2 ] ){
lng_tmp = lng_space;
break;
}
@@ -294,13 +297,13 @@ std::string MISC::listtostr( const std::list< std::string >& list_in )
//
std::string MISC::remove_space( const std::string& str )
{
- std::string str_space = " ";
- size_t lng_space = str_space.length();
+ const char* str_space = "\xE3\x80\x80"; // " " 空白
+ const size_t lng_space = 3;
size_t lng = str.length();
if( lng == 0 ) return str;
- if( str.find( " " ) == std::string::npos ) return str;
+ if( str.find_first_of( ' ' ) == std::string::npos ) return str;
// 前
size_t i = 0;
@@ -312,7 +315,7 @@ std::string MISC::remove_space( const std::string& str )
// 全角
else if( str[ i ] == str_space[ 0 ] &&
str[ i +1 ] == str_space[ 1 ] &&
- ( lng_space == 2 || str[ i +2 ] == str_space[ 2 ] ) ) i += lng_space;
+ str[ i +2 ] == str_space[ 2 ] ) i += lng_space;
else break;
}
@@ -327,7 +330,7 @@ std::string MISC::remove_space( const std::string& str )
else if( i2 +1 >= lng_space &&
str[ i2 - lng_space +1 ] == str_space[ 0 ] &&
str[ i2 - lng_space +2 ] == str_space[ 1 ] &&
- ( lng_space == 2 || str[ i2 - lng_space +3 ] == str_space[ 2 ] ) ) i2 -= lng_space;
+ str[ i2 - lng_space +3 ] == str_space[ 2 ] ) i2 -= lng_space;
else break;
}
@@ -340,7 +343,7 @@ std::string MISC::remove_space( const std::string& str )
//
std::string MISC::remove_spaces( const std::string& str )
{
- if( str.empty() ) return std::string();
+ if( str.empty() ) return str;
size_t l = 0, r = str.length();
@@ -352,13 +355,15 @@ std::string MISC::remove_spaces( const std::string& str )
// 最後の文字の位置は文字数より1少ない
size_t p = r - 1;
- while( p > 0
+ while( p > l
&& ( str[p] == '\n'
|| str[p] == '\r'
|| str[p] == '\t'
- || str[p] == ' ' ) ){ --p; --r; }
+ || str[p] == ' ' ) ) --p;
- return str.substr( l, r - l );
+ if( l == 0 && p == r - 1 ) return str;
+
+ return str.substr( l, p + 1 - l );
}
@@ -447,6 +452,63 @@ std::string MISC::replace_str( const std::string& str, const std::string& str1,
return str_out;
}
+//
+// str1 を str2 に置き換え(ignore case)
+//
+std::string MISC::replace_casestr( const std::string& str, const std::string& str1, const std::string& str2 )
+{
+ std::string str_out;
+
+//#ifndef _GNU_SOURCE
+#if 0
+ // 日本語ロケールだとラテン文字[a-zA-Z]以外はcase判定しないもよう
+ // コードは簡潔になるが遅くなるし旨味がない
+
+ const char *p0 = str.c_ctr(), *p1;
+
+ while( ( p1 = strcasestr( p0, str1.c_str() ) ) != NULL ){
+ str_out.append( p0, p1 - p0 );
+ str_out.append( str2 );
+ p0 = p1 + str1.length();
+ }
+#else
+ char accept[2] = { 0, 0 };
+
+ if( ( str1[ 0 ] >= 'A' && str1[ 0 ] <= 'Z' ) || ( str1[ 0 ] >= 'a' && str1[ 0 ] <= 'z' ) ){
+ accept[ 0 ] = str1[ 0 ] & ~0x20;
+ accept[ 1 ] = str1[ 0 ] | 0x20;
+ }
+ else accept[ 0 ] = str1[ 0 ];
+
+ const char *p0, *p1, *p2;
+ p0 = p1 = str.c_str();
+
+ struct searcheither{
+ inline static const char* fn( const char *p, const char* a ){
+ while( *p != a[ 0 ] && *p != a[ 1 ] && *p != '\0' ) ++p;
+ return ( *p == '\0' ) ? NULL : p;
+ }
+ };
+
+ while( ( p2 = searcheither::fn( p1, accept ) ) != NULL ){
+
+ if( strncasecmp( p2, str1.c_str(), str1.length() ) == 0 ){
+ str_out.append( p0, p2 - p0 );
+ str_out.append( str2 );
+ p0 = p1 = p2 + str1.length();
+ continue;
+ }
+ p1 = p2 + 1;
+ }
+#endif
+
+ if( p0 == str.c_str() ) return str;
+
+ str_out.append( str, p0 - str.c_str(), std::string::npos );
+
+ return str_out;
+}
+
//
// list_inから str1 を str2 に置き換えてリストを返す
@@ -456,7 +518,7 @@ std::list< std::string > MISC::replace_str_list( const std::list< std::string >&
{
std::list< std::string > list_out;
std::list< std::string >::const_iterator it = list_in.begin();
- for( ; it != list_in.end(); ++it ) list_out.push_back( replace_str( *it, str1, str2 ) );
+ for( ; it != list_in.end(); ++it ) list_out.push_back( MISC::replace_str( *it, str1, str2 ) );
return list_out;
}
@@ -488,24 +550,6 @@ std::string MISC::replace_newlines_to_str( const std::string& str_in, const std:
}
-//
-// " を \" に置き換え
-//
-std::string MISC::replace_quot( const std::string& str )
-{
- return MISC::replace_str( str, "\"", "\\\"" );
-}
-
-
-//
-// \" を " に置き換え
-//
-std::string MISC::recover_quot( const std::string& str )
-{
- return MISC::replace_str( str, "\\\"", "\"" );
-}
-
-
//
// str 中に含まれている str2 の 数を返す
//
@@ -581,10 +625,14 @@ int MISC::str_to_uint( const char* str, size_t& dig, size_t& n )
//
std::string MISC::itostr( const int n )
{
+#if __cplusplus < 201103L
std::ostringstream ss;
ss << n;
return ss.str();
+#else
+ return std::to_string( n );
+#endif
}
@@ -672,7 +720,7 @@ std::string MISC::cut_str( const std::string& str, const unsigned int maxsize )
const size_t outstr_length = outstr.length();
for( pos = 0, lng_str = 0; pos < outstr_length; pos += byte ){
- MISC::utf8toucs2( outstr.c_str()+pos, byte );
+ byte = MISC::utf8bytes( outstr.c_str() + pos );
if( byte > 1 ) lng_str += 2;
else ++lng_str;
if( lng_str >= maxsize ) break;
@@ -830,9 +878,9 @@ std::string MISC::regex_unescape( const std::string& str )
//
// HTMLエスケープ
//
-// include_url : URL中でもエスケープする( デフォルト = true )
+// completely : URL中でもエスケープする( デフォルト = true )
//
-std::string MISC::html_escape( const std::string& str, const bool include_url )
+std::string MISC::html_escape( const std::string& str, const bool completely )
{
if( str.empty() ) return str;
@@ -846,15 +894,15 @@ std::string MISC::html_escape( const std::string& str, const bool include_url )
char tmpchar = str.c_str()[ pos ];
// URL中はエスケープしない場合
- if( ! include_url )
+ if( ! completely )
{
// URLとして扱うかどうか
// エスケープには影響がないので loose_url としておく
- if( scheme != SCHEME_NONE ) is_url = is_url_char( str.c_str() + pos, true );
+ if( scheme != SCHEME_NONE ) is_url = MISC::is_url_char( str.c_str() + pos, true );
// URLスキームが含まれているか判別
int len = 0;
- if( ! is_url ) scheme = is_url_scheme( str.c_str() + pos, &len );
+ if( ! is_url ) scheme = MISC::is_url_scheme( str.c_str() + pos, &len );
// URLスキームが含まれていた場合は文字数分進めてループに戻る
if( len > 0 )
@@ -865,17 +913,9 @@ std::string MISC::html_escape( const std::string& str, const bool include_url )
}
}
- // include_url = false でURL中ならエスケープしない
+ // completely = false でURL中ならエスケープしない
if( is_url ) str_out += tmpchar;
- else if( tmpchar == '&' )
- {
- const int bufsize = 64;
- char out_char[ bufsize ];
- int n_in, n_out;
- const int type = DBTREE::decode_char( str.c_str() + pos, n_in, out_char, n_out, false );
- if( type == DBTREE::NODE_NONE ) str_out += "&amp;";
- else str_out += tmpchar;
- }
+ else if( tmpchar == '&' ) str_out += "&amp;";
else if( tmpchar == '\"' ) str_out += "&quot;";
else if( tmpchar == '<' ) str_out += "&lt;";
else if( tmpchar == '>' ) str_out += "&gt;";
@@ -884,7 +924,8 @@ std::string MISC::html_escape( const std::string& str, const bool include_url )
#ifdef _DEBUG
if( str != str_out ){
- std::cout << "MISC::html_escape\nstr = " << str << std::endl
+ std::cout << "MISC::html_escape" << std::endl
+ << "str = " << str << std::endl
<< "out = " << str_out << std::endl;
}
#endif
@@ -899,23 +940,24 @@ std::string MISC::html_escape( const std::string& str, const bool include_url )
std::string MISC::html_unescape( const std::string& str )
{
if( str.empty() ) return str;
- if( str.find( "&" ) == std::string::npos ) return str;
+ if( str.find_first_of( '&' ) == std::string::npos ) return str;
std::string str_out;
- const size_t str_length = str.length();
+ const char* pos = str.c_str();
+ const char* pos_end = pos + str.length();
- for( size_t pos = 0; pos < str_length; ++pos ){
+ while( pos < pos_end ){
- const int bufsize = 64;
- char out_char[ bufsize ];
- int n_in, n_out;
- DBTREE::decode_char( str.c_str() + pos, n_in, out_char, n_out, false );
+ // '&' までコピーする
+ while( *pos != '&' && *pos != '\0' ) str_out.push_back( *pos++ );
+ if( pos >= pos_end ) break;
- if( n_out ){
- str_out += out_char;
- pos += n_in -1;
- }
- else str_out += str.c_str()[ pos ];
+ // エスケープ用の文字参照をデコード
+ if( memcmp( pos , "&quot;", 6 ) == 0 ){ str_out.push_back( '"' ); pos += 6; }
+ else if( memcmp( pos, "&amp;", 5 ) == 0 ){ str_out.push_back( '&' ); pos += 5; }
+ else if( memcmp( pos, "&lt;", 4 ) == 0 ){ str_out.push_back( '<' ); pos += 4; }
+ else if( memcmp( pos, "&gt;", 4 ) == 0 ){ str_out.push_back( '>' ); pos += 4; }
+ else str_out.push_back( *pos++ );
}
#ifdef _DEBUG
@@ -930,6 +972,246 @@ std::string MISC::html_unescape( const std::string& str )
+//
+// 特殊文字のデコード内部処理
+//
+// strは'&'で始まる文字列を指定すること
+// completely = true の時は'"' '&' '<' '>'も含めて変換する
+//
+static std::string spchar_impl( const char* str, int& n_in, const char pre_char, const bool completely )
+{
+ const int bufsize = 32;
+ char out_char[ bufsize ];
+ int n_out;
+ const int type = DBTREE::decode_char( str, n_in, out_char, n_out, false );
+
+ // 改行、タブ、スペースの処理
+ if( type == DBTREE::NODE_SP && pre_char != ' ' ){
+ out_char[ 0 ] = ' ';
+ n_out = 1;
+ }
+ // 変換できない文字
+ else if( type == DBTREE::NODE_NONE ){
+ out_char[ 0 ] = *str;
+ n_out = 1;
+ n_in = 1;
+ }
+ // エスケープする文字の場合は元に戻す
+ else if( ! completely && n_out == 1 ){
+ switch( *out_char ){
+ case '"':
+ out_char[ 0 ] = '&'; out_char[ 1 ] = 'q'; out_char[ 2 ] = 'u';
+ out_char[ 3 ] = 'o'; out_char[ 4 ] = 't'; out_char[ 5 ] = ';';
+ n_out = 6;
+ break;
+ case '&':
+ out_char[ 0 ] = '&'; out_char[ 1 ] = 'a'; out_char[ 2 ] = 'm';
+ out_char[ 3 ] = 'p'; out_char[ 4 ] = ';';
+ n_out = 5;
+ break;
+ case '<':
+ out_char[ 0 ] = '&'; out_char[ 1 ] = 'l'; out_char[ 2 ] = 't';
+ out_char[ 3 ] = ';';
+ n_out = 4;
+ break;
+ case '>':
+ out_char[ 0 ] = '&'; out_char[ 1 ] = 'g'; out_char[ 2 ] = 't';
+ out_char[ 3 ] = ';';
+ n_out = 4;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return std::string( out_char, n_out );
+}
+
+
+//
+// HTMLをプレーンテキストに変換する
+//
+std::string MISC::to_plain( const std::string& html )
+{
+ if( html.empty() ) return html;
+ if( html.find_first_of( '<' ) == std::string::npos
+ && html.find_first_of( '&' ) == std::string::npos ) return html;
+
+ std::string str_out;
+ const char* pos = html.c_str();
+ const char* pos_end = pos + html.length();
+
+ while( pos < pos_end ){
+
+ // '<' か '&' までコピーする
+ while( *pos != '<' && *pos != '&' && *pos != '\0' ) str_out.push_back( *pos++ );
+ if( pos >= pos_end ) break;
+
+ // タグを取り除く
+ if( *pos == '<' ){
+ while( *pos != '>' && *pos != '\0' ) pos++;
+ if( *pos == '>' ) ++pos;
+ continue;
+ }
+
+ // 文字参照を処理する
+ if( *pos == '&' ){
+ int n_in;
+ char pre = str_out.length() ? *( str_out.end() - 1 ) : 0;
+ str_out += spchar_impl( pos, n_in, pre, true );
+ pos += n_in;
+ }
+ }
+
+#ifdef _DEBUG
+ if( html != str_out )
+ std::cout << "MISC::to_plain" << std::endl
+ << "html = " << html << std::endl
+ << "plain = " << str_out << std::endl;
+#endif
+
+ return str_out;
+}
+
+
+//
+// HTMLをPango markupテキストに変換する
+//
+//
+std::string MISC::to_markup( const std::string& html )
+{
+ if( html.empty() ) return html;
+ if( html.find_first_of( '<' ) == std::string::npos
+ && html.find_first_of( '&' ) == std::string::npos ) return html;
+
+ const char* pos = html.c_str();
+ const char* pos_end = pos + html.length();
+ std::string markuptxt;
+
+ while( pos < pos_end ){
+
+ // '<' か '&' までコピーする
+ while( *pos != '<' && *pos != '&' && *pos != '\0' ) markuptxt.push_back( *pos++ );
+ if( pos >= pos_end ) break;
+
+ // タグを処理する
+ if( *pos == '<' ){
+ ++pos;
+
+ // <mark>と<span>タグは色を変える
+ if( memcmp( pos, "mark", 4 ) == 0 || memcmp( pos, "span", 4 ) == 0 ){
+ std::string classname = ( ( *pos ) == 'm' ) ? "mark" : "";
+ pos += 4;
+ if( memcmp( pos, " class=\"", 8 ) == 0 ){
+ pos += 8;
+ const char* pos_name = pos;
+ while( *pos != '"' && *pos != '\0' ) ++pos;
+ classname = std::string( pos_name, pos - pos_name );
+ if( *pos != '\0' ) ++pos;
+ }
+
+ markuptxt += "<span";
+
+ if( classname.size() ){
+ CORE::Css_Manager* mgr = CORE::get_css_manager();
+ int classid = mgr->get_classid( classname );
+ if( classid != -1 ){
+ CORE::CSS_PROPERTY css = mgr->get_property( classid );
+ if( css.color != -1 ) markuptxt += " color=\"" + mgr->get_color( css.color ) + "\"";
+ if( css.bg_color != -1 ) markuptxt += " background=\"" + mgr->get_color( css.bg_color ) + "\"";
+ }
+ }
+
+ while( *pos != '>' && *pos != '\0' ) markuptxt.push_back( *pos++ );
+ markuptxt += ">";
+ if( *pos != '\0' ) ++pos;
+ continue;
+ }
+
+ // </mark> は </sapn>に置換する
+ if( memcmp( pos, "/mark>" , 6 ) == 0 || memcmp( pos, "/span>" , 6 ) == 0 ){
+ pos += 6;
+ markuptxt += "</span>";
+ continue;
+ }
+
+ // XXX その他のタグは取り除く
+ while( *pos != '>' && *pos != '\0' ) ++pos;
+ if( *pos == '>' ) ++pos;
+ continue;
+ }
+
+ // 文字参照を処理する
+ if( *pos == '&' ){
+ if( pos[ 1 ] == 'q' && pos[ 2 ] == 'u' && pos[ 3 ] == 'o' && pos[ 4 ] == 't' && pos[ 5 ] == ';' ){
+ markuptxt.push_back( '"' );
+ pos += 6;
+ }
+ else{
+ int n_in;
+ char pre = markuptxt.length() ? markuptxt[ markuptxt.length() - 1 ] : 0;
+ markuptxt += spchar_impl( pos, n_in, pre, false );
+ if( n_in == 1 && markuptxt[ markuptxt.length() - 1 ] == '&' ){
+ markuptxt += "amp;";
+ }
+ pos += n_in;
+ }
+ }
+ }
+
+#ifdef _DEBUG
+ if( html != markuptxt )
+ std::cout << "MISC::to_markup" << std::endl
+ << "html = " << html << std::endl
+ << "markup = " << markuptxt << std::endl;
+#endif
+
+ return markuptxt;
+}
+
+
+//
+// HTMLの文字参照をデコード
+//
+// completely = true の時は'"' '&' '<' '>'もデコードする
+//
+std::string MISC::chref_decode( const char* str, const int lng, const bool completely )
+{
+ std::string str_out;
+
+ if( lng <= 0 ) return str_out;
+ if( memchr( str, '&', lng ) == NULL ){
+ str_out.assign( str, lng );
+ return str_out;
+ }
+
+ const char *pos = str;
+ const char *pos_end = str + lng;
+
+ while( pos < pos_end ){
+
+ // '&' までコピーする
+ while( *pos != '&' && pos < pos_end ) str_out.push_back( *pos++ );
+ if( pos >= pos_end ) break;
+
+ // 文字参照のデコード
+ int n_in;
+ str_out += spchar_impl( pos, n_in, 0, completely );
+ pos += n_in;
+ }
+
+#ifdef _DEBUG
+ if( str != str_out ){
+ std::cout << "MISC::chref_decode" << std::endl
+ << "str = " << str << std::endl
+ << "out = " << str_out << std::endl;
+ }
+#endif
+
+ return str_out;
+}
+
+
//
// URL中のスキームを判別する
//
@@ -970,13 +1252,15 @@ int MISC::is_url_scheme_impl( const char* str_in, int* length )
if( *( str_in + len ) == 's' ) ++len;
}
// sssp
- // デフォルトでモザイクを解除するのでimg.2ch以外のアドレスにはリンクを張らない
- else if( *str_in == 's' && *( str_in + 1 ) == 's' && *( str_in + 2 ) == 's' && *( str_in + 3 ) == 'p'
- && *( str_in + 7 ) == 'i' && *( str_in + 8 ) == 'm' && *( str_in + 9 ) == 'g' && *( str_in + 10 ) == '.'
- && *( str_in + 11 ) == '2' && *( str_in + 12 ) == 'c' && *( str_in + 13 ) == 'h'
- )
- {
- scheme = SCHEME_SSSP;
+ else if( *str_in == 's' && *( str_in + 1 ) == 's' && *( str_in + 2 ) == 's' && *( str_in + 3 ) == 'p' ){
+ if( *( str_in + 7 ) == 'i' && *( str_in + 8 ) == 'm' && *( str_in + 9 ) == 'g' && *( str_in + 10 ) == '.'
+ && *( str_in + 11 ) == '2' && *( str_in + 12 ) == 'c' && *( str_in + 13 ) == 'h'){
+ scheme = SCHEME_SSSP;
+ }
+ else{
+ // XXX img.2ch以外のアドレスはHTTPスキームにする
+ scheme = SCHEME_HTTP;
+ }
len = 4;
}
@@ -1042,52 +1326,52 @@ bool MISC::is_url_char( const char* str_in, const bool loose_url )
//
// URLデコード
//
-std::string MISC::url_decode( const std::string& url )
+std::string MISC::url_decode( const char* url, const size_t n )
{
- if( url.empty() ) return std::string();
+ std::string decoded;
+ if( n == 0 ) return decoded;
- const size_t url_length = url.length();
-
- std::vector< char > decoded( url_length + 1, '\0' );
-
- unsigned int a, b;
- for( a = 0, b = a; a < url_length; ++a, ++b )
+ unsigned int a;
+ for( a = 0; a < n; ++a )
{
- if( url[a] == '%' && ( a + 2 < url_length ) )
+ if( url[a] == '%' && ( a + 2 ) < n )
{
char src[3] = { url[ a + 1 ], url[ a + 2 ], '\0' };
char tmp[3] = { '\0', '\0', '\0' };
if( chrtobin( src, tmp ) == 2 )
{
+ // 改行はLFにする
+ if( *tmp == '\n' && !decoded.empty() && *--decoded.end() == '\r' )
+ decoded.erase( --decoded.end() );
// '%4A' など、2文字が変換できていること
- decoded[b] = *tmp;
+ decoded.push_back( *tmp );
a += 2;
}
else
{
// 変換失敗は、単なる '%' 文字として扱う
- decoded[b] = url[a];
+ decoded.push_back( url[a] );
}
}
else if( url[a] == '+' )
{
- decoded[b] = ' ';
+ decoded.push_back( ' ' );
}
else
{
- decoded[b] = url[a];
+ decoded.push_back( url[a] );
}
}
- return decoded.data();
+ return decoded;
}
//
// url エンコード
//
-std::string MISC::url_encode( const char* str, const size_t n )
+std::string MISC::url_encode( const char* str, const size_t n, const CharCode coding )
{
if( str[ n ] != '\0' ){
ERRMSG( "url_encode : invalid input." );
@@ -1095,62 +1379,76 @@ std::string MISC::url_encode( const char* str, const size_t n )
}
std::string str_encoded;
+ JDLIB::Iconv* icv = NULL;
+ if( coding != CHARCODE_UTF8 ) icv = new JDLIB::Iconv( CHARCODE_UTF8, coding );
- for( size_t i = 0; i < n; i++ ){
+ size_t pos = 0;
+ while( pos < n ){
- unsigned char c = str[ i ];
const int tmplng = 16;
char str_tmp[ tmplng ];
- if( ! ( 'a' <= c && c <= 'z' ) &&
- ! ( 'A' <= c && c <= 'Z' ) &&
- ! ( '0' <= c && c <= '9' ) &&
- ( c != '*' ) &&
- ( c != '-' ) &&
- ( c != '.' ) &&
- ( c != '@' ) &&
- ( c != '_' )){
+ if( icv ){
+ size_t pos_start = pos;
+ while( str[ pos ] & 0x80 ) ++pos;
+ if( pos != pos_start ){
+ int byte_out;
+ const std::string str_enc = icv->convert( str + pos_start, pos - pos_start, byte_out );
- snprintf( str_tmp, tmplng , "%%%02x", c );
+ // マルチバイト文字は全てパーセントエンコードする
+ for( int i = 0; i < byte_out; ++i ){
+ unsigned char c = str_enc[ i ];
+ snprintf( str_tmp, tmplng , "%%%02X", c );
+ str_encoded += str_tmp;
+ }
+
+ if( pos >= n ) break;
+ }
}
- else {
+
+ unsigned char c = str[ pos ];
+
+ // 非予約文字はそのまま
+ if( ( 'a' <= c && c <= 'z' ) || ( 'A' <= c && c <= 'Z' )
+ || ( '0' <= c && c <= '9' )
+ || ( c == '-' ) || ( c == '.' ) || ( c == '_' ) || ( c == '~' ) ){
str_tmp[ 0 ] = c;
str_tmp[ 1 ] = '\0';
}
+ // スペースは'+'に置換
+ else if( c == ' ' ){
+ str_tmp[ 0 ] = '+';
+ str_tmp[ 1 ] = '\0';
+ }
+ // 改行を正規化
+ else if( c == '\n' ){
+ str_tmp[ 0 ] = '%'; str_tmp[ 1 ] = '0'; str_tmp[ 2 ] = 'D'; // CR ( %0d )
+ str_tmp[ 3 ] = '%'; str_tmp[ 4 ] = '0'; str_tmp[ 5 ] = 'A'; // LF ( %0a )
+ str_tmp[ 6 ] = '\0';
+ }
+ // CR は無視
+ else if( c == '\r' ){
+ str_tmp[ 0 ] = '\0';
+ }
+ // その他はパーセントエンコード
+ else{
+ snprintf( str_tmp, tmplng , "%%%02X", c );
+ }
str_encoded += str_tmp;
+ ++pos;
}
+ if( icv ) delete icv;
+
return str_encoded;
}
-std::string MISC::url_encode( const std::string& str )
-{
- return url_encode( str.c_str(), str.length() );
-}
-
-
//
-// 文字コード変換して url エンコード
+// 半角スペースまたは "" 単位で区切って url エンコード
//
-// str は UTF-8 であること
-//
-std::string MISC::charset_url_encode( const std::string& str, const std::string& charset )
-{
- if( charset.empty() || charset == "UTF-8" ) return MISC::url_encode( str.c_str(), str.length() );
-
- const std::string str_enc = MISC::Iconv( str, "UTF-8", charset );
- return MISC::url_encode( str_enc.c_str(), str_enc.length() );
-}
-
-
-//
-// 文字コード変換して url エンコード
-//
-// ただし半角スペースのところを+に置き換えて区切る
-//
-std::string MISC::charset_url_encode_split( const std::string& str, const std::string& charset )
+std::string MISC::url_encode_split( const std::string& str, const CharCode charcode )
{
std::list< std::string > list_str = MISC::split_line( str );
std::list< std::string >::iterator it = list_str.begin();
@@ -1158,7 +1456,7 @@ std::string MISC::charset_url_encode_split( const std::string& str, const std::s
for( ; it != list_str.end(); ++it ){
if( it != list_str.begin() ) str_out += "+";
- str_out += MISC::charset_url_encode( *it, charset );
+ str_out += MISC::url_encode( it->c_str(), it->length(), charcode );
}
return str_out;
@@ -1212,31 +1510,6 @@ std::string MISC::base64( const std::string& str )
-
-//
-// 文字コードを coding_from から coding_to に変換
-//
-// 遅いので連続的な処理が必要な時は使わないこと
-//
-std::string MISC::Iconv( const std::string& str, const std::string& coding_from, const std::string& coding_to )
-{
- if( coding_from == coding_to ) return str;
-
- char* str_bk = ( char* ) malloc( str.length() + 64 );
- strcpy( str_bk, str.c_str() );
-
- JDLIB::Iconv* libiconv = new JDLIB::Iconv( coding_from, coding_to );
- int byte_out;
-
- const std::string str_enc = libiconv->convert( str_bk, strlen( str_bk ), byte_out );
-
- delete libiconv;
- free( str_bk );
-
- return str_enc;
-}
-
-
//
// 「&#数字;」形式の数字参照文字列の中の「数字」部分の文字列長
//
@@ -1255,7 +1528,7 @@ int MISC::spchar_number_ln( const char* in_char, int& offset )
// offset == 2 なら 10 進数、3 なら16進数
if( in_char[ offset ] == 'x' || in_char[ offset ] == 'X' ) ++offset;
- // UCS2の2バイトの範囲でデコードするので最大65535
+ // UCS-4の範囲でデコードするので最大1114111
// デコードするとき「;」で終端されていなくてもよい
// デコード可能かチェック
@@ -1426,7 +1699,7 @@ std::string MISC::decode_spchar_number( const std::string& str )
const int num = MISC::decode_spchar_number( str.c_str()+i, offset, lng );
char out_char[ 64 ];
- const int n_out = MISC::ucs2toutf8( num, out_char );
+ const int n_out = MISC::cptoutf8( num, out_char );
if( ! n_out ){
str_out += str[ i ];
continue;
@@ -1442,168 +1715,6 @@ std::string MISC::decode_spchar_number( const std::string& str )
}
-//
-// utf-8 -> ucs2 変換
-//
-// 入力 : utfstr 入力文字 (UTF-8)
-//
-// 出力 : byte 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す
-//
-// 戻り値 : ucs2
-//
-int MISC::utf8toucs2( const char* utfstr, int& byte )
-{
- int ucs2 = 0;
- byte = 0;
-
- if( utfstr[ 0 ] == '\0' ) return '\0';
-
- else if( ( ( unsigned char ) utfstr[ 0 ] & 0xf0 ) == 0xe0 ){
- byte = 3;
- ucs2 = utfstr[ 0 ] & 0x0f;
- ucs2 = ( ucs2 << 6 ) + ( utfstr[ 1 ] & 0x3f );
- ucs2 = ( ucs2 << 6 ) + ( utfstr[ 2 ] & 0x3f );
- }
-
- else if( ( ( unsigned char ) utfstr[ 0 ] & 0x80 ) == 0 ){ // ascii
- byte = 1;
- ucs2 = utfstr[ 0 ];
- }
-
- else if( ( ( unsigned char ) utfstr[ 0 ] & 0xe0 ) == 0xc0 ){
- byte = 2;
- ucs2 = utfstr[ 0 ] & 0x1f;
- ucs2 = ( ucs2 << 6 ) + ( utfstr[ 1 ] & 0x3f );
- }
-
- else if( ( ( unsigned char ) utfstr[ 0 ] & 0xf8 ) == 0xf0 ){
- byte = 4;
- ucs2 = utfstr[ 0 ] & 0x07;
- ucs2 = ( ucs2 << 6 ) + ( utfstr[ 1 ] & 0x3f );
- ucs2 = ( ucs2 << 6 ) + ( utfstr[ 2 ] & 0x3f );
- ucs2 = ( ucs2 << 6 ) + ( utfstr[ 3 ] & 0x3f );
- }
-
- // 不正なUTF8
- else {
- byte = 1;
- ucs2 = utfstr[ 0 ];
- ERRMSG( "MISC::utf8toucs2 : invalid code = " + MISC::itostr( ucs2 ) );
- }
-
- return ucs2;
-}
-
-
-
-
-//
-// ucs2 -> utf8 変換
-//
-// 出力 : utfstr 変換後の文字
-//
-// 戻り値 : バイト数
-//
-int MISC::ucs2toutf8( const int ucs2, char* utfstr )
-{
- int byte = 0;
-
- if( ucs2 <= 0x7f ){ // ascii
- byte = 1;
- utfstr[ 0 ] = ucs2;
- }
-
- else if( ucs2 <= 0x07ff ){
- byte = 2;
- utfstr[ 0 ] = ( 0xc0 ) + ( ucs2 >> 6 );
- utfstr[ 1 ] = ( 0x80 ) + ( ucs2 & 0x3f );
- }
-
- else if( ucs2 <= 0xffff){
- byte = 3;
- utfstr[ 0 ] = ( 0xe0 ) + ( ucs2 >> 12 );
- utfstr[ 1 ] = ( 0x80 ) + ( ( ucs2 >>6 ) & 0x3f );
- utfstr[ 2 ] = ( 0x80 ) + ( ucs2 & 0x3f );
- }
-
- else{
- byte = 4;
- utfstr[ 0 ] = ( 0xf0 ) + ( ucs2 >> 18 );
- utfstr[ 1 ] = ( 0x80 ) + ( ( ucs2 >>12 ) & 0x3f );
- utfstr[ 2 ] = ( 0x80 ) + ( ( ucs2 >>6 ) & 0x3f );
- utfstr[ 3 ] = ( 0x80 ) + ( ucs2 & 0x3f );
- }
-
- utfstr[ byte ] = 0;
- return byte;
-}
-
-
-//
-// ucs2 の種類
-//
-int MISC::get_ucs2mode( const int ucs2 )
-{
- if( ucs2 >= 0x0000 && ucs2 <= 0x007f ) return UCS2MODE_BASIC_LATIN;
- if( ucs2 >= 0x3040 && ucs2 <= 0x309f ) return UCS2MODE_HIRA;
- if( ucs2 >= 0x30a0 && ucs2 <= 0x30ff ) return UCS2MODE_KATA;
-
- return UCS2MODE_OTHER;
-}
-
-//
-// WAVEDASHなどのWindows系UTF-8文字をUnix系文字と相互変換
-//
-std::string MISC::utf8_fix_wavedash( const std::string& str, const int mode )
-{
- // WAVE DASH 問題
- const size_t size = 4;
- const unsigned char Win[size][4] = {
- { 0xef, 0xbd, 0x9e, '\0' }, // FULLWIDTH TILDE (U+FF5E)
- { 0xe2, 0x80, 0x95, '\0' }, // HORIZONTAL BAR (U+2015)
- { 0xe2, 0x88, 0xa5, '\0' }, // PARALLEL TO (U+2225)
- { 0xef, 0xbc, 0x8d, '\0' } // FULLWIDTH HYPHEN-MINUS (U+FF0D)
- };
- const unsigned char Unix[size][4] = {
- { 0xe3, 0x80, 0x9c, '\0' }, // WAVE DASH (U+301C)
- { 0xe2, 0x80, 0x94, '\0' }, // EM DASH(U+2014)
- { 0xe2, 0x80, 0x96, '\0' }, // DOUBLE VERTICAL LINE (U+2016)
- { 0xe2, 0x88, 0x92, '\0' } // MINUS SIGN (U+2212)
- };
-
- std::string ret(str);
-
- if( mode == WINtoUNIX ){
-
- for( size_t i = 0; i < ret.length(); i++ ) {
- for( size_t s = 0; s < size; s++ ) {
- if( ret[ i ] != (char)Win[ s ][ 0 ] || ret[ i+1 ] != (char)Win[ s ][ 1 ] || ret[ i+2 ] != (char)Win[ s ][ 2 ] )
- continue;
- for( size_t t = 0; t < 3; t++ )
- ret[ i+t ] = (char)Unix[ s ][ t ];
- i += 2;
- break;
- }
- }
-
- }else{
-
- for( size_t i = 0; i < ret.length(); i++ ) {
- for( size_t s = 0; s < size; s++ ) {
- if( ret[ i ] != (char)Unix[ s ][ 0 ] || ret[ i+1 ] != (char)Unix[ s ][ 1 ] || ret[ i+2 ] != (char)Unix[ s ][ 2 ] )
- continue;
- for( size_t t = 0; t < 3; t++ )
- ret[ i+t ] = (char)Win[ s ][ t ];
- i += 2;
- break;
- }
- }
- }
-
- return ret;
-}
-
-
//
// str を大文字化
//
@@ -1709,13 +1820,13 @@ std::string MISC::getenv_limited( const char *name, const size_t size )
{
if( ! name || ! getenv( name ) ) return std::string();
- std::vector< char > env( size + 1, '\0' );
- strncpy( env.data(), getenv( name ), size );
+ std::string env( getenv( name ) );
+ if( env.length() > size ) env.resize( size );
#ifdef _WIN32
- return recover_path( Glib::locale_to_utf8( std::string( env.data() ) );
+ return recover_path( Glib::locale_to_utf8( env ) );
#else
- return env.data();
+ return env;
#endif
}
@@ -1746,7 +1857,7 @@ std::vector< std::string > MISC::recover_path( std::vector< std::string >&& list
list_ret.push_back( MISC::recover_path( *it ) );
return list_ret;
#else
- return list_str;
+ return std::move( list_str );
#endif
}
@@ -1866,7 +1977,7 @@ void MISC::asc( const char* str1, std::string& str2, std::vector< int >& table_p
}
}
- while( !flag_hkana && hkana_table1[ i ][ 0 ][ 0 ] != '\0' ){
+ while( hkana_table1[ i ][ 0 ][ 0 ] != '\0' ){
if( in1 == hkana_table1[ i ][ 0 ][ 0 ]
&& in2 == hkana_table1[ i ][ 0 ][ 1 ]
@@ -1877,6 +1988,7 @@ void MISC::asc( const char* str1, std::string& str2, std::vector< int >& table_p
if( dakuten ) pos += 3;
flag_hkana = true;
+ break;
}
++i;
}
@@ -1889,3 +2001,61 @@ void MISC::asc( const char* str1, std::string& str2, std::vector< int >& table_p
++pos;
}
}
+
+
+//
+// UTF8文字列の正規化
+//
+// str1 : 変換する文字列
+// str2 : 出力先
+// table_pos : 置き換えた文字列の位置
+//
+void MISC::norm( const char* str1, std::string& str2, std::vector< int >& table_pos )
+{
+ size_t pos1 = 0;
+ Glib::ustring ustr;
+ std::string str_norm;
+ int lng;
+
+ while( str1[ pos1 ] != '\0' ){
+
+ int nbytes = MISC::utf8bytes( str1 + pos1 );
+ if( nbytes <= 1 ){
+ str2.push_back( str1[ pos1 ] );
+ if( table_pos.capacity() ) table_pos.push_back( pos1 );
+ pos1++;
+ continue;
+ }
+
+ // 異字体は纏める
+ int next = MISC::utf8tocp( str1 + pos1 + nbytes, lng );
+ int nchars = 1;
+ if( ( next >= 0x180b && next <= 0x180d ) ||
+ ( next >= 0xfe00 && next <= 0xfe0f ) ||
+ ( next >= 0xe0100 && next <= 0xe01ef ) ){
+ nchars++;
+ nbytes += lng;
+ }
+
+ ustr.assign( str1 + pos1, nchars );
+ str_norm = ustr.normalize( Glib::NORMALIZE_NFKD );
+
+ lng = str_norm.length();
+#if 0
+ if( pos2 + lng >= n - 1 ){
+ ERRMSG( "MISC::asc : buffer overflow." );
+ break;
+ }
+#endif
+
+ std::copy( str_norm.begin(), str_norm.end(), std::back_inserter( str2 ) );
+ if( table_pos.capacity() ){
+ table_pos.push_back( pos1 );
+ std::fill_n( std::back_inserter( table_pos ), lng -1, -1 );
+ }
+
+ pos1 += nbytes;
+ }
+
+ //if( table_pos.capacity() ) table_pos.push_back( pos1 );
+}
diff --git a/src/jdlib/miscutil.h b/src/jdlib/miscutil.h
index a8c37c52..4962ca75 100644
--- a/src/jdlib/miscutil.h
+++ b/src/jdlib/miscutil.h
@@ -5,6 +5,8 @@
#ifndef _MISCUTIL_H
#define _MISCUTIL_H
+#include "charcode.h"
+
#include <string>
#include <cstring>
#include <list>
@@ -25,24 +27,6 @@ namespace MISC
SCHEME_SSSP
};
- // get_ucs2mode()の戻り値
- enum
- {
- UCS2MODE_BASIC_LATIN = 0,
- UCS2MODE_HIRA,
- UCS2MODE_KATA,
-
- UCS2MODE_OTHER
- };
-
-
- // utf8_fix_wavedash のモード
- enum
- {
- UNIXtoWIN = 0,
- WINtoUNIX
- };
-
// str を "\n" ごとに区切ってlistにして出力
std::list< std::string > get_lines( const std::string& str );
@@ -95,6 +79,9 @@ namespace MISC
// str1 を str2 に置き換え
std::string replace_str( const std::string& str, const std::string& str1, const std::string& str2 );
+ // str1 を str2 に置き換え( ignore case 版 )
+ std::string replace_casestr( const std::string& str, const std::string& str1, const std::string& str2 );
+
// list_inから str1 を str2 に置き換えてリストを返す
std::list< std::string > replace_str_list( const std::list< std::string >& list_in,
const std::string& str1, const std::string& str2 );
@@ -103,10 +90,10 @@ namespace MISC
std::string replace_newlines_to_str( const std::string& str_in, const std::string& replace );
// " を \" に置き換え
- std::string replace_quot( const std::string& str );
+ inline std::string replace_quot( const std::string& str ){ return MISC::replace_str( str, "\"", "\\\"" ); }
// \" を " に置き換え
- std::string recover_quot( const std::string& str );
+ inline std::string recover_quot( const std::string& str ){ return MISC::replace_str( str, "\\\"", "\"" ); }
// str 中に含まれている str2 の 数を返す
int count_str( const std::string& str, const std::string& str2 );
@@ -146,12 +133,22 @@ namespace MISC
std::string regex_unescape( const std::string& str );
// HTMLエスケープ
- // include_url : URL中でもエスケープする( デフォルト = true )
- std::string html_escape( const std::string& str, const bool include_url = true );
+ // completely : URL中でもエスケープする( デフォルト = true )
+ std::string html_escape( const std::string& str, const bool completely = true );
// HTMLアンエスケープ
std::string html_unescape( const std::string& str );
+ // HTMLをプレーンテキストに変換する
+ std::string to_plain( const std::string& html );
+
+ // HTMLをPango Markupテキストに変換する
+ std::string to_markup( const std::string& html );
+
+ // HTML文字参照をデコード( completely=trueの場合は '&' '<' '>' '"' を含める )
+ std::string chref_decode( const char* str, const int lng, const bool completely = true );
+ inline std::string chref_decode( const std::string& str, const bool completely = true ){ return MISC::chref_decode( str.c_str(), str.length(), completely ); }
+
// URL中のスキームを判別する
// 戻り値 : スキームタイプ
// length : "http://"等の文字数
@@ -167,27 +164,22 @@ namespace MISC
bool is_url_char( const char* str_in, const bool loose_url );
// URLデコード
- std::string url_decode( const std::string& url );
+ std::string url_decode( const char* url, const size_t n );
+ inline std::string url_decode( const std::string& url ){ return url_decode( url.c_str(), url.length() ); }
// urlエンコード
- std::string url_encode( const char* str, const size_t n );
- std::string url_encode( const std::string& str );
+ std::string url_encode( const char* str, const size_t n, const CharCode charcode = CHARCODE_UTF8 );
+ inline std::string url_encode( const std::string& str, const CharCode charcode = CHARCODE_UTF8 )
+ {
+ return url_encode( str.c_str(), str.length(), charcode );
+ }
- // 文字コードを変換して url エンコード
- // str は UTF-8 であること
- std::string charset_url_encode( const std::string& str, const std::string& charset );
-
- // 文字コード変換して url エンコード
- // ただし半角スペースのところを+に置き換えて区切る
- std::string charset_url_encode_split( const std::string& str, const std::string& charset );
+ // 半角スペースまたは "" 単位で区切って url エンコード
+ std::string url_encode_split( const std::string& str, const CharCode charcode );
// BASE64
std::string base64( const std::string& str );
- // 文字コードを coding_from から coding_to に変換
- // 遅いので連続的な処理が必要な時は使わないこと
- std::string Iconv( const std::string& str, const std::string& coding_from, const std::string& coding_to );
-
// 「&#数字;」形式の数字参照文字列の中の「数字」部分の文字列長
//
// in_char: 入力文字列、in_char[0] == "&" && in_char[1] == "#" であること
@@ -214,23 +206,6 @@ namespace MISC
// str に含まれる「&#数字;」形式の数字参照文字列を全てユニーコード文字に変換する
std::string decode_spchar_number( const std::string& str );
- // utf-8 -> ucs2 変換
- // 入力 : utfstr 入力文字 (UTF-8)
- // 出力 : byte 長さ(バイト) utfstr が ascii なら 1, UTF-8 なら 2 or 3 or 4 を入れて返す
- // 戻り値 : ucs2
- int utf8toucs2( const char* utfstr, int& byte );
-
- // ucs2 の種類
- int get_ucs2mode( const int ucs2 );
-
- // ucs2 -> utf8 変換
- // 出力 : utfstr 変換後の文字
- // 戻り値 : バイト数
- int ucs2toutf8( const int ucs2, char* utfstr );
-
- // WAVEDASHなどのWindows系UTF-8文字をUnix系文字と相互変換
- std::string utf8_fix_wavedash( const std::string& str, const int mode );
-
// str を大文字化
std::string toupper_str( const std::string& str );
@@ -264,6 +239,10 @@ namespace MISC
// table_pos : 置き換えた文字列の位置
void asc( const char* str1, std::string& str2, std::vector< int >& table_pos );
+ // UTF-8文字列(str1) -> 正規化文字列(str2)
+ // table_pos : 置き換えた文字列の位置
+ void norm( const char* str1, std::string& str2, std::vector< int >& table_pos );
+
// URL中のスキームを判別する
inline int is_url_scheme( const char* str_in, int* length )
diff --git a/src/jdlib/refptr_lock.h b/src/jdlib/refptr_lock.h
index 120f29a7..6e04032e 100644
--- a/src/jdlib/refptr_lock.h
+++ b/src/jdlib/refptr_lock.h
@@ -32,7 +32,8 @@ namespace JDLIB
}
- T* operator -> () const noexcept { return m_p; }
+ T* operator -> () noexcept { return m_p; }
+ const T* operator -> () const noexcept { return m_p; }
bool operator == ( const T *p ) const { return( m_p == p ); }
bool operator != ( const T *p ) const { return( m_p != p ); }
bool operator ! () const { return ( m_p == NULL ); }
diff --git a/src/jdlib/ssl.cpp b/src/jdlib/ssl.cpp
deleted file mode 100644
index a9028ca0..00000000
--- a/src/jdlib/ssl.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-// ライセンス: GPL2
-
-//#define _DEBUG
-#include "jddebug.h"
-
-#include "ssl.h"
-
-using namespace JDLIB;
-
-
-#ifdef USE_GNUTLS
-
-#include <cstring>
-
-// gnutls 使用
-
-void JDLIB::init_ssl()
-{
-#ifdef _DEBUG
- std::cout << "init_ssl(gnutls)\n";
-#endif
-
- gnutls_global_init();
-}
-
-void JDLIB::deinit_ssl()
-{
-#ifdef _DEBUG
- std::cout << "deinit_ssl(gnutls)\n";
-#endif
-
- gnutls_global_deinit();
-}
-
-
-JDSSL::JDSSL()
- : m_session( 0 ),
- m_cred( 0 )
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::JDSSL(gnutls)\n";
-#endif
-}
-
-
-JDSSL::~JDSSL()
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::~JDSSL(gnutls)\n";
-#endif
-
- close();
-}
-
-
-bool JDSSL::connect( const int soc, const char *host )
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::connect(gnutls)\n";
-#endif
-
- if( soc < 0 ) return false;
- if( m_session ) return false;
- if( m_cred ) return false;
-
- int ret;
-
- ret = gnutls_init( &m_session, GNUTLS_CLIENT );
- if( ret != 0 ){
- m_errmsg = "gnutls_init failed";
- return false;
- }
-
-#if GNUTLS_VERSION_NUMBER >= 0x030406
- ret = gnutls_certificate_allocate_credentials( &m_cred );
- assert( ret == GNUTLS_E_SUCCESS );
- ret = gnutls_certificate_set_x509_system_trust( m_cred );
- assert( ret >= 0 );
-
- ret = gnutls_server_name_set( m_session, GNUTLS_NAME_DNS, host, strlen( host ) );
- assert( ret == GNUTLS_E_SUCCESS );
-
- ret = gnutls_set_default_priority( m_session );
- assert( ret == GNUTLS_E_SUCCESS );
- ret = gnutls_credentials_set( m_session, GNUTLS_CRD_CERTIFICATE, m_cred );
- assert( ret == GNUTLS_E_SUCCESS );
-
- gnutls_session_set_verify_cert( m_session, host, 0 );
-
- gnutls_transport_set_int( m_session, soc );
- gnutls_handshake_set_timeout( m_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT );
-
-#else // GNUTLS_VERSION_NUMBER < 0x030406
-
-#if GNUTLS_VERSION_NUMBER >= 0x020108
- // gnutls >= 2.1.7 (unreleased)
- gnutls_priority_set_direct( m_session, "NORMAL:%COMPAT", NULL );
-#else // GNUTLS_VERSION_NUMBER >= 0x020108
- static const int priority_prot[] = { GNUTLS_SSL3, 0 };
- // DEPRECATED (gnutls >= 2.1.4 gnutls =< 2.1.6)
- // UNDEPRECATED (gnutls >= 2.1.7)
- gnutls_set_default_priority( m_session );
- // _GNUTLS_GCC_ATTR_DEPRECATE (gnutls >= 2.12.0)
- gnutls_protocol_set_priority( m_session, priority_prot );
-#endif // GNUTLS_VERSION_NUMBER >= 0x020108
-
- gnutls_transport_set_ptr( m_session, (gnutls_transport_ptr_t)(long) soc );
- gnutls_certificate_allocate_credentials( &m_cred );
- gnutls_credentials_set( m_session, GNUTLS_CRD_CERTIFICATE, m_cred );
- gnutls_server_name_set( m_session, GNUTLS_NAME_DNS, host, strlen( host ) );
-
-#endif // GNUTLS_VERSION_NUMBER >= 0x030406
-
- do {
- ret = gnutls_handshake( m_session );
- } while( ret < 0 && gnutls_error_is_fatal( ret ) == 0 );
-
- if( ret < 0 ) {
- m_errmsg = "JDSSL::connect(gnutls) *** Handshake failed: ";
- m_errmsg += gnutls_strerror( ret );
-#if GNUTLS_VERSION_NUMBER >= 0x030406
- if( ret == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR ) {
- gnutls_certificate_type_t type = gnutls_certificate_type_get( m_session );
- const unsigned status = gnutls_session_get_verify_cert_status( m_session );
- gnutls_datum_t out;
- ret = gnutls_certificate_verification_status_print( status, type, &out, 0 );
- if( ret == GNUTLS_E_SUCCESS ) {
- m_errmsg += "\nJDSSL::connect(gnutls) - cert verify output: ";
- m_errmsg += reinterpret_cast< const char* >( out.data );
- gnutls_free( out.data );
- }
- }
-#endif
- return false;
- }
-
-#ifdef _DEBUG
-#if GNUTLS_VERSION_NUMBER >= 0x030110
- char* desc = gnutls_session_get_desc( m_session );
- assert( desc );
- std::cout << "JDSSL::connect(gnutls) - Session info: " << desc << std::endl;
- gnutls_free( desc );
-#else
- std::cout << "JDSSL::connect(gnutls)" << std::endl;
-#endif
-#endif // _DEBUG
-
- return true;
-}
-
-
-bool JDSSL::close()
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::close(gnutls)\n";
-#endif
-
- if( m_session ){
- gnutls_bye( m_session, GNUTLS_SHUT_RDWR );
- gnutls_deinit( m_session );
- m_session = 0;
- }
- if( m_cred ){
- gnutls_certificate_free_credentials( m_cred );
- m_cred = 0;
- }
-
- return true;
-}
-
-
-int JDSSL::write( const char* buf, const size_t bufsize )
-{
- int tmpsize;
- do {
- tmpsize = gnutls_record_send( m_session, buf, bufsize );
- } while( tmpsize == GNUTLS_E_AGAIN || tmpsize == GNUTLS_E_INTERRUPTED );
-
-#ifdef _DEBUG
- std::cout << "JDSSL::write(gnutls) tmpsize = " << tmpsize << "; bufsize = " << bufsize << std::endl;
-#endif
-
- if( tmpsize < 0 ) m_errmsg = "gnutls_record_send failed";
-
- return tmpsize;
-}
-
-
-int JDSSL::read( char* buf, const size_t bufsize )
-{
- int tmpsize;
- do {
- tmpsize = gnutls_record_recv( m_session, buf, bufsize );
- } while( tmpsize == GNUTLS_E_AGAIN || tmpsize == GNUTLS_E_INTERRUPTED );
-
-#ifdef _DEBUG
- std::cout << "JDSSL::read(gnutls) tmpsize = " << tmpsize << "; bufsize = " << bufsize << std::endl;
-#endif
-
-#ifdef GNUTLS_E_PREMATURE_TERMINATION
- if( tmpsize == GNUTLS_E_PREMATURE_TERMINATION || tmpsize == GNUTLS_E_INVALID_SESSION ) {
- // Transfer-Encoding: chuncked のときはデータの長さが分からない
- // そのため受信エラーをデータ無しに置き換えて受信終了を判断する
- return 0;
- }
-#endif
- if( tmpsize < 0 ) m_errmsg = "gnutls_record_recv failed";
-
- return tmpsize;
-}
-
-#else ////////////////////////////////////////////////////////////////////
-
-// OpenSSL 使用
-
-void JDLIB::init_ssl()
-{
-#ifdef _DEBUG
- std::cout << "init_ssl(openssl)\n";
-#endif
-}
-
-void JDLIB::deinit_ssl()
-{
-#ifdef _DEBUG
- std::cout << "deinit_ssl(openssl)\n";
-#endif
-}
-
-
-JDSSL::JDSSL()
- : m_ctx( NULL ),
- m_ssl( NULL )
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::JDSSL(openssl)\n";
-#endif
-}
-
-
-JDSSL::~JDSSL()
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::~JDSSL(openssl)\n";
-#endif
-
- close();
-}
-
-
-bool JDSSL::connect( const int soc, const char *host )
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::connect(openssl)\n";
-#endif
-
- if( soc < 0 ) return false;
- if( m_ctx ) return false;
- if( m_ssl ) return false;
-
- SSL_library_init();
- m_ctx = SSL_CTX_new( SSLv23_client_method() );
- if( ! m_ctx ){
- m_errmsg = "SSL_CTX_new failed";
- return false;
- }
-
- m_ssl = SSL_new( m_ctx );
- if( ! m_ssl ){
- m_errmsg = "SSL_new failed";
- return false;
- }
-
- if( SSL_set_fd( m_ssl, soc ) == 0 ){
- m_errmsg = "SSL_set_fd failed";
- return false;
- }
-
- SSL_set_tlsext_host_name( m_ssl, host ) ;
- if( SSL_connect( m_ssl ) != 1 ){
- m_errmsg = "SSL_connect failed";
- return false;
- }
-
-#ifdef _DEBUG
- std::cout << "connect ok\n";
-#endif
-
- return true;
-}
-
-
-bool JDSSL::close()
-{
-#ifdef _DEBUG
- std::cout << "JDSSL::close(openssl)\n";
-#endif
-
- if( m_ssl ){
- SSL_shutdown( m_ssl );
- SSL_free( m_ssl );
- m_ssl = NULL;
- }
- if( m_ctx ){
- SSL_CTX_free( m_ctx );
- m_ctx = NULL;
- }
-
- return true;
-}
-
-
-int JDSSL::write( const char* buf, const size_t bufsize )
-{
- int tmpsize = SSL_write( m_ssl, buf, bufsize );
- if( tmpsize < 0 ) m_errmsg = "SSL_write failed";
-
- return tmpsize;
-}
-
-
-int JDSSL::read( char* buf, const size_t bufsize )
-{
- int tmpsize = SSL_read( m_ssl, buf, bufsize );
- if( tmpsize < 0 ) m_errmsg = "SSL_read failed";
-
- return tmpsize;
-}
-
-#endif
diff --git a/src/jdlib/ssl.h b/src/jdlib/ssl.h
deleted file mode 100644
index 3ee5cc60..00000000
--- a/src/jdlib/ssl.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// ライセンス: GPL2
-
-//
-// SSL ローダ
-//
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef USE_GNUTLS
-#include <gnutls/gnutls.h>
-#else
-#include <openssl/ssl.h>
-
-// gdkmm/device.h で定義される set_key マクロと衝突する
-#ifdef set_key
-#undef set_key
-#endif
-
-#endif
-
-#include <string>
-
-namespace JDLIB
-{
- class JDSSL
- {
- std::string m_errmsg;
-
-#ifdef USE_GNUTLS
- gnutls_session_t m_session;
-
-#if GNUTLS_VERSION_NUMBER >= 0x020000
- gnutls_certificate_credentials_t m_cred;
-#else // GNUTLS_VERSION_NUMBER >= 0x020000
- // DEPRECATED (gnutls >= 2.x)
- gnutls_certificate_credentials m_cred;
-#endif // GNUTLS_VERSION_NUMBER >= 0x020000
-
-#else // USE_GNUTLS
- SSL_CTX *m_ctx;
- SSL* m_ssl;
-#endif // USE_GNUTLS
-
- public:
-
- JDSSL();
- virtual ~JDSSL();
-
- const std::string& get_errmsg(){ return m_errmsg; }
-
- bool connect( const int soc, const char* host );
- bool close();
-
- int write( const char* buf, const size_t bufsize );
- int read( char* buf, const size_t bufsize );
- };
-
- void init_ssl();
- void deinit_ssl();
-}
diff --git a/src/jdversion.h b/src/jdversion.h
index 9607f60f..551a1358 100644
--- a/src/jdversion.h
+++ b/src/jdversion.h
@@ -20,8 +20,8 @@
#define MAJORVERSION 0
#define MINORVERSION 1
#define MICROVERSION 0
-#define JDDATE_FALLBACK "20190413"
-#define JDTAG ""
+#define JDDATE_FALLBACK "171004"
+#define JDTAG "a"
//---------------------------------
diff --git a/src/linkfiltermanager.cpp b/src/linkfiltermanager.cpp
index 79fa06c2..0ba1ff68 100644
--- a/src/linkfiltermanager.cpp
+++ b/src/linkfiltermanager.cpp
@@ -144,8 +144,8 @@ bool Linkfilter_Manager::exec( const std::string& url, const std::string& link,
std::vector< LinkFilterItem >::iterator it = m_list_cmd.begin();
for( ; it != m_list_cmd.end(); ++it ){
- const std::string query = ( *it ).url;
- const std::string cmd = ( *it ).cmd;
+ const std::string& query = ( *it ).url;
+ const std::string& cmd = ( *it ).cmd;
#ifdef _DEBUG
std::cout << "query = " << query << std::endl
@@ -154,15 +154,7 @@ bool Linkfilter_Manager::exec( const std::string& url, const std::string& link,
if( ! regex.exec( query, link, offset, icase, newline, usemigemo, wchar ) ) continue;
// \0 ... \9 までのcmd文字列を置換
- std::string cmd_out = cmd;
- char rep_text[] = "\\0";
- for( int i = 0; i < 9; i++ ){
- if( regex.pos( i ) == -1 ){
- continue;
- }
- rep_text[ 1 ] = '0' + i;
- cmd_out = MISC::replace_str( cmd_out, rep_text, regex.str( i ) );
- }
+ std::string cmd_out = regex.replace( cmd );
// queryと一致したら実行
CORE::get_usrcmd_manager()->exec( cmd_out, url, link, selection, 0 );
diff --git a/src/linkfiltermanager.h b/src/linkfiltermanager.h
index 238fcd0a..d3a83b9b 100644
--- a/src/linkfiltermanager.h
+++ b/src/linkfiltermanager.h
@@ -26,7 +26,7 @@ namespace CORE
public:
Linkfilter_Manager();
- virtual ~Linkfilter_Manager() noexcept {}
+ virtual ~Linkfilter_Manager() noexcept = default;
std::vector< LinkFilterItem >& get_list(){ return m_list_cmd; }
void save_xml();
diff --git a/src/livepref.h b/src/livepref.h
index 1deac624..fa3de360 100644
--- a/src/livepref.h
+++ b/src/livepref.h
@@ -35,7 +35,7 @@ namespace CORE
public:
LivePref( Gtk::Window* parent, const std::string& url );
- ~LivePref() noexcept {}
+ ~LivePref() noexcept = default;
private:
diff --git a/src/loginbe.cpp b/src/loginbe.cpp
index 29fa8aa7..03b101fb 100644
--- a/src/loginbe.cpp
+++ b/src/loginbe.cpp
@@ -121,7 +121,7 @@ void LoginBe::start_login()
data.contenttype = "application/x-www-form-urlencoded";
data.str_post = "m=" + MISC::url_encode( get_username() );
data.str_post += "&p=" + MISC::url_encode( get_passwd() );
- data.str_post += "&submit=" + MISC::charset_url_encode( "登録", "EUC-JP" );
+ data.str_post += "&submit=" + MISC::url_encode( std::string( "登録" ), CHARCODE_EUCJP );
logout();
if( ! m_rawdata ) m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA );
diff --git a/src/loginp2.cpp b/src/loginp2.cpp
index c7ce60f6..5a807abe 100644
--- a/src/loginp2.cpp
+++ b/src/loginp2.cpp
@@ -133,8 +133,7 @@ void Loginp2::start_login()
data.str_post += "&regist_cookie=1"; // p2(rep2)
data.str_post += "&ctl_register_cookie=1"; // p2.2ch.net(2012/01/24修正)
data.str_post += "&register_cookie=1"; // p2.2ch.net(2012/01/24修正)
-// data.str_post += "&submit_member=" + MISC::charset_url_encode( "ユーザログイン", "MS932" ); // 2009/12/20 仕様変更
- data.str_post += "&submit_userlogin=" + MISC::charset_url_encode( "ユーザログイン", "MS932" );
+ data.str_post += "&submit_userlogin=" + MISC::url_encode( std::string( "ユーザログイン" ), CHARCODE_SJIS );
logout();
if( ! m_rawdata ) m_rawdata = ( char* )malloc( SIZE_OF_RAWDATA );
diff --git a/src/main.cpp b/src/main.cpp
index 2282d630..9c52d0dc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,6 +4,10 @@
//#define _DEBUG_MEM_PROFILE
#include "jddebug.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include "config/globalconf.h"
#include "winmain.h"
@@ -13,7 +17,7 @@
#include "jdlib/miscmsg.h"
#include "jdlib/miscutil.h"
-#include "jdlib/ssl.h"
+#include "jdlib/jdsocket.h"
#include "jdlib/jdregex.h"
#include <signal.h>
@@ -483,7 +487,10 @@ int main( int argc, char **argv )
}
#endif
-#if ! GLIB_CHECK_VERSION(2, 46, 0)
+ // デフォルトのbackend指定
+ Glib::setenv( "PANGOCAIRO_BACKEND", "fc", 0 );
+
+#if !GLIB_CHECK_VERSION(2,45,5)
#ifdef _DEBUG_MEM_PROFILE
g_mem_set_vtable( glib_mem_profiler_table );
atexit( g_mem_profile );
@@ -528,7 +535,7 @@ int main( int argc, char **argv )
else MISC::ERRMSG( "failed to connect to gnome session manager" );
#endif
- JDLIB::init_ssl();
+ JDLIB::tlslib_init();
// 全体設定ロード
bool init = !( CONFIG::load_conf() );
@@ -634,7 +641,7 @@ int main( int argc, char **argv )
xsmp_session_end( &xsmpdata );
#endif
- JDLIB::deinit_ssl();
+ JDLIB::tlslib_deinit();
return 0;
}
diff --git a/src/mainitempref.h b/src/mainitempref.h
index 96e5c7dd..e8f2085e 100644
--- a/src/mainitempref.h
+++ b/src/mainitempref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
MainItemPref( Gtk::Window* parent, const std::string& url );
- ~MainItemPref() noexcept {}
+ ~MainItemPref() noexcept = default;
private:
diff --git a/src/maintoolbar.cpp b/src/maintoolbar.cpp
index 3d66c911..ce81116c 100644
--- a/src/maintoolbar.cpp
+++ b/src/maintoolbar.cpp
@@ -65,6 +65,10 @@ MainToolBar::MainToolBar() :
pack_buttons();
}
+
+MainToolBar::~MainToolBar() noexcept = default;
+
+
// ボタンのパッキング
// virtual
void MainToolBar::pack_buttons()
diff --git a/src/maintoolbar.h b/src/maintoolbar.h
index a87f9964..b07aa5be 100644
--- a/src/maintoolbar.h
+++ b/src/maintoolbar.h
@@ -41,7 +41,7 @@ namespace CORE
public:
MainToolBar();
- ~MainToolBar() noexcept {}
+ ~MainToolBar() noexcept;
protected:
diff --git a/src/menuslots.cpp b/src/menuslots.cpp
index 8d229109..b96f7a11 100644
--- a/src/menuslots.cpp
+++ b/src/menuslots.cpp
@@ -1041,6 +1041,17 @@ void Core::slot_filter_pref()
}
+//
+// 置換文字列の編集
+//
+void Core::slot_replace_pref()
+{
+ SKELETON::PrefDiag* pref= CORE::PrefDiagFactory( NULL, CORE::PREFDIAG_REPLACESTR, URL_REPLACESTR );
+ pref->run();
+ delete pref;
+}
+
+
//
// about:config
//
@@ -1142,7 +1153,7 @@ void Core::slot_search_cache()
//
void Core::slot_show_cache_board()
{
- const std::string url = DBTREE::url_subject( BOARD::get_admin()->get_current_url() );
+ const std::string url = DBTREE::url_boardbase( BOARD::get_admin()->get_current_url() );
if( ! url.empty() ) CORE::core_set_command( "open_board_showlog", url );
}
@@ -1270,7 +1281,7 @@ void Core::slot_create_vboard()
//
void Core::slot_show_bbs()
{
- CORE::core_set_command( "open_board" , DBTREE::url_subject( ENVIRONMENT::get_jdbbs() ), "newtab" );
+ CORE::core_set_command( "open_board" , DBTREE::url_boardbase( ENVIRONMENT::get_jdbbs() ), "newtab" );
}
@@ -1279,7 +1290,7 @@ void Core::slot_show_bbs()
//
void Core::slot_show_old2ch()
{
- CORE::core_set_command( "open_board" , DBTREE::url_subject( ENVIRONMENT::get_jd2chlog() ), "newtab" );
+ CORE::core_set_command( "open_board" , DBTREE::url_boardbase( ENVIRONMENT::get_jd2chlog() ), "newtab" );
}
diff --git a/src/message/Makefile.am b/src/message/Makefile.am
index 04af07a8..a626934c 100644
--- a/src/message/Makefile.am
+++ b/src/message/Makefile.am
@@ -17,6 +17,7 @@ noinst_HEADERS = \
messageview.h \
post.h \
toolbar.h \
+ logitem.h \
logmanager.h \
confirmdiag.h \
logitem.h
diff --git a/src/message/confirmdiag.cpp b/src/message/confirmdiag.cpp
index ec911a32..e39335e3 100644
--- a/src/message/confirmdiag.cpp
+++ b/src/message/confirmdiag.cpp
@@ -30,6 +30,10 @@ ConfirmDiag::ConfirmDiag( const std::string& url, const std::string& message )
grab_ok();
}
+
+ConfirmDiag::~ConfirmDiag() noexcept = default;
+
+
void ConfirmDiag::slot_switch_page( GtkNotebookPage*, guint page )
{
if( get_notebook().get_nth_page( page ) == get_detail() ){
diff --git a/src/message/confirmdiag.h b/src/message/confirmdiag.h
index c11a48fd..439f3d8d 100644
--- a/src/message/confirmdiag.h
+++ b/src/message/confirmdiag.h
@@ -18,6 +18,7 @@ namespace MESSAGE
public:
ConfirmDiag( const std::string& url, const std::string& message );
+ ~ConfirmDiag() noexcept;
Gtk::CheckButton& get_chkbutton(){ return m_chkbutton; }
diff --git a/src/message/logitem.h b/src/message/logitem.h
index ada1e2d8..74aafb8b 100644
--- a/src/message/logitem.h
+++ b/src/message/logitem.h
@@ -9,6 +9,7 @@
#include "messageadmin.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include <list>
diff --git a/src/message/messageview.cpp b/src/message/messageview.cpp
index cf0eb85a..7c15f1cd 100644
--- a/src/message/messageview.cpp
+++ b/src/message/messageview.cpp
@@ -31,11 +31,13 @@ MessageViewMain::MessageViewMain( const std::string& url, const std::string& msg
// ツールバーのスレタイトルを編集不可にする
MESSAGE::get_admin()->show_entry_new_subject( false );
+ const std::string& subject = DBTREE::article_modified_subject( get_url() );
+
// メインウィンドウのタイトルに表示する文字
- set_title( "[ 書き込み ] " + DBTREE::article_subject( get_url() ) );
+ set_title( "[ 書き込み ] " + MISC::to_plain( subject ) );
// ツールバーにスレ名を表示
- set_label( DBTREE::article_subject( get_url() ) );
+ set_label( MISC::to_markup( subject ), true );
}
@@ -152,7 +154,7 @@ void MessageViewMain::reload()
MESSAGE::get_admin()->show_entry_new_subject( true );
// メインウィンドウのタイトルに表示する文字
- set_title( "[ 新スレ作成 ] " + DBTREE::article_subject( get_url() ) );
+ set_title( "[ 新スレ作成 ] " + MISC::to_plain( DBTREE::article_modified_subject( get_url() ) ) );
}
@@ -202,5 +204,5 @@ void MessageViewNew::write_impl( const std::string& msg )
void MessageViewNew::reload()
{
- CORE::core_set_command( "open_board", DBTREE::url_subject( get_url() ), "true" );
+ CORE::core_set_command( "open_board", DBTREE::url_boardbase( get_url() ), "true" );
}
diff --git a/src/message/messageview.h b/src/message/messageview.h
index a3428930..26b89b0e 100644
--- a/src/message/messageview.h
+++ b/src/message/messageview.h
@@ -27,7 +27,7 @@ namespace MESSAGE
{
public:
MessageViewNew( const std::string& url, const std::string& msg );
- ~MessageViewNew() noexcept {}
+ ~MessageViewNew() noexcept = default;
void reload() override;
diff --git a/src/message/messageviewbase.cpp b/src/message/messageviewbase.cpp
index bae7f4c5..2a80d9ac 100644
--- a/src/message/messageviewbase.cpp
+++ b/src/message/messageviewbase.cpp
@@ -15,6 +15,7 @@
#include "skeleton/editview.h"
#include "skeleton/detaildiag.h"
+#include "jdlib/misccharcode.h"
#include "jdlib/miscutil.h"
#include "jdlib/misctime.h"
#include "jdlib/misctrip.h"
@@ -85,7 +86,7 @@ MessageViewBase::MessageViewBase( const std::string& url )
m_max_line = DBTREE::line_number( get_url() ) * 2;
m_max_str = DBTREE::message_count( get_url() );
- m_iconv = new JDLIB::Iconv( "UTF-8", DBTREE::board_charset( get_url() ) );;
+ m_iconv = new JDLIB::Iconv( CHARCODE_UTF8, DBTREE::board_charcode( get_url() ) );;
m_lng_iconv = m_max_str * 3;
if( ! m_lng_iconv ) m_lng_iconv = MAX_STR_ICONV;
@@ -145,7 +146,7 @@ Gtk::Window* MessageViewBase::get_parent_win()
//
// メインウィンドウのURLバーなどに表示する)
//
-std::string MessageViewBase::url_for_copy()
+std::string MessageViewBase::url_for_copy() const
{
return DBTREE::url_readcgi( get_url(), 0, 0 );
}
@@ -673,7 +674,7 @@ void MessageViewBase::write()
const bool newline = true;
const bool usemigemo = false;
const bool wchar = false;
- if( regex.exec( "%26%23[0-9]*%3b", msg, offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.exec( "%26%23[0-9]+%3b", msg, offset, icase, newline, usemigemo, wchar ) ){
SKELETON::MsgDiag mdiag( get_parent_win(),
"ユニコード文字が含まれていますが、この板ではユニコード文字は文字化けします(BBS_UNICODE=change)。\n\n書き込みますか?",
@@ -761,7 +762,7 @@ bool MessageViewBase::slot_button_press( GdkEventButton* event )
//
// フォントの更新
//
-void MessageViewBase::relayout()
+void MessageViewBase::relayout( const bool completely )
{
init_font( CONFIG::get_fontname( FONT_MESSAGE ) );
init_color();
@@ -909,12 +910,6 @@ void MessageViewBase::slot_switch_page( GtkNotebookPage*, guint page )
std::string new_subject = MESSAGE::get_admin()->get_new_subject();
if( ! new_subject.empty() ) set_label( new_subject );
- // URLを除外してエスケープ
- const bool include_url = false;
- std::string msg;
- if( m_text_message ) msg = MISC::html_escape( m_text_message->get_text(), include_url );
- msg = MISC::replace_str( msg, "\n", " <br> " );
-
std::stringstream ss;
// 名前 + トリップ
@@ -929,7 +924,7 @@ void MessageViewBase::slot_switch_page( GtkNotebookPage*, guint page )
std::string trip;
if( trip_pos != std::string::npos )
{
- trip = MISC::get_trip( name_field.substr( trip_pos + 1 ), DBTREE::board_charset( get_url() ) );
+ trip = MISC::get_trip( name_field.substr( trip_pos + 1 ), DBTREE::board_charcode( get_url() ) );
}
ss << name;
@@ -944,9 +939,29 @@ void MessageViewBase::slot_switch_page( GtkNotebookPage*, guint page )
struct timeval tv;
struct timezone tz;
gettimeofday( &tv, &tz );
- ss << MISC::timettostr( tv.tv_sec, MISC::TIME_WEEK );
+ ss << MISC::timettostr( tv.tv_sec, MISC::TIME_WEEK ) << " ID:\?\?\?<>";
- ss << " ID:???" << "<>" << msg << "<>\n";
+ if( m_text_message ){
+ std::string msg = m_text_message->get_text();
+ if( DBTREE::get_unicode( get_url() ) == "change" ){
+ // MS932等に無い文字を数値参照にするために文字コードを変換する
+ int byte_out;
+ std::string str_enc = m_iconv->convert( msg.c_str(), msg.length(), byte_out );
+ msg = MISC::Iconv( str_enc, DBTREE::board_charcode( get_url() ), CHARCODE_UTF8 );
+ }
+ else{
+ // XXX 2chでは文字実態参照はデコードされない
+ msg = MISC::chref_decode( msg );
+ }
+
+ // URLを除外してエスケープ
+ const bool include_url = false;
+ msg = MISC::html_escape( msg, include_url );
+
+ ss << MISC::replace_str( msg, "\n", " <br> " );
+ }
+
+ ss << "<>\n";
#ifdef _DEBUG
std::cout << ss.str() << std::endl;
@@ -1015,7 +1030,7 @@ void MessageViewBase::show_status()
{
int byte_out;
const char* msgc = message.c_str();
- std::string str_enc = m_iconv->convert( (char*)msgc, strlen( msgc ), byte_out );
+ std::string str_enc = m_iconv->convert( (char*)msgc, message.length(), byte_out );
m_lng_str_enc = str_enc.length();
// 特殊文字の文字数を計算
diff --git a/src/message/messageviewbase.h b/src/message/messageviewbase.h
index a5af09a3..c5fb0026 100644
--- a/src/message/messageviewbase.h
+++ b/src/message/messageviewbase.h
@@ -96,7 +96,7 @@ namespace MESSAGE
Gtk::Window* get_parent_win() override;
// コピー用のURL
- std::string url_for_copy() override;
+ std::string url_for_copy() const override;
// コマンド
bool set_command( const std::string& command,
@@ -107,7 +107,7 @@ namespace MESSAGE
bool is_loading() const override;
// 規制中や行数や文字列がオーバーして書き込めない
- bool is_broken() override { return ( ! m_str_pass.empty() || m_over_lines || m_over_lng ); }
+ bool is_broken() const override { return ( ! m_str_pass.empty() || m_over_lines || m_over_lng ); }
// キーを押した
bool slot_key_press( GdkEventKey* event ) override;
@@ -115,7 +115,7 @@ namespace MESSAGE
void clock_in() override;
void write() override;
void reload() override {}
- void relayout() override;
+ void relayout( const bool completely = false ) override;
void close_view() override;
void redraw_view() override;
void focus_view() override;
diff --git a/src/message/post.cpp b/src/message/post.cpp
index df779005..05d6acad 100644
--- a/src/message/post.cpp
+++ b/src/message/post.cpp
@@ -215,8 +215,7 @@ void Post::receive_finish()
std::cout << "Post::receive_finish\n";
#endif
- std::string charset = DBTREE::board_charset( m_url );
- JDLIB::Iconv* libiconv = new JDLIB::Iconv( charset, "UTF-8" );
+ JDLIB::Iconv* libiconv = new JDLIB::Iconv( DBTREE::board_charcode( m_url ), CHARCODE_UTF8 );
int byte_out;
m_return_html = libiconv->convert( m_rawdata, m_lng_rawdata, byte_out );
delete libiconv;
@@ -315,10 +314,8 @@ void Post::receive_finish()
newline = false; // . に改行をマッチさせる
// Smaba24規制の場合
// ERROR - 593 60 sec たたないと書けません。(1回目、8 sec しかたってない)
- // 忍法帖規制の場合 ( samba秒だけ取得する。 )
- // ERROR:修行が足りません(Lv=2)。しばらくたってから投稿してください。(48 sec)
- // この板のsambaは samba=30 sec
- if( regex.exec( "ERROR( +- +593 +|:.+samba=)([0-9]+) +sec", m_errmsg, offset, icase, newline, usemigemo, wchar ) ){
+ // ERROR: Samba24:Caution 25 秒たたないと書けません。(1 回目、24 秒しかたってない)
+ if( regex.exec( "(ERROR +- +593|ERROR: +Samba24:Caution|) +([0-9]+) +", m_errmsg, offset, icase, newline, usemigemo, wchar ) ){
time_t sec = atoi( regex.str( 2 ).c_str() );
#ifdef _DEBUG
std::cout << "samba = " << sec << std::endl;
@@ -362,6 +359,10 @@ void Post::receive_finish()
std::cout << "location: [" << location() << "]\n";
#endif
+ // クッキーのセット
+ const bool empty_cookies = DBTREE::board_list_cookies_for_write( m_url ).empty();
+ if( list_cookies.size() ) DBTREE::board_set_list_cookies_for_write( m_url, list_cookies );
+
// 成功
if( title.find( "書きこみました" ) != std::string::npos
|| tag_2ch.find( "true" ) != std::string::npos
@@ -372,9 +373,6 @@ void Post::receive_finish()
std::cout << "write ok" << std::endl;
#endif
- // クッキーのセット
- DBTREE::board_set_list_cookies_for_write( m_url, list_cookies );
-
DBTREE::article_update_writetime( m_url );
emit_sigfin();
return;
@@ -384,7 +382,7 @@ void Post::receive_finish()
else if( m_count < 1 && // 永久ループ防止
( title.find( "書き込み確認" ) != std::string::npos
|| tag_2ch.find( "cookie" ) != std::string::npos
- || ( ! DBTREE::board_list_cookies_for_write( m_url ).size() && list_cookies.size() )
+ || ( empty_cookies && list_cookies.size() )
) ){
clear();
@@ -414,12 +412,9 @@ void Post::receive_finish()
DBTREE::board_analyze_keyword_for_write( m_url, m_return_html );
// 現在のメッセージにキーワードが付加されていない時は付け加える
- const std::string keyword = DBTREE::board_keyword_for_write( m_url );
+ const std::string& keyword = DBTREE::board_keyword_for_write( m_url );
if( ! keyword.empty() && m_msg.find( keyword ) == std::string::npos ) m_msg += "&" + keyword;
- // クッキーのセット
- DBTREE::board_set_list_cookies_for_write( m_url, list_cookies );
-
++m_count; // 永久ループ防止
post_msg();
@@ -434,12 +429,9 @@ void Post::receive_finish()
DBTREE::board_analyze_keyword_for_write( m_url, m_return_html );
// 現在のメッセージにキーワードが付加されていない時は付け加える
- const std::string keyword = DBTREE::board_keyword_for_write( m_url );
+ const std::string& keyword = DBTREE::board_keyword_for_write( m_url );
if( ! keyword.empty() && m_msg.find( keyword ) == std::string::npos ) m_msg += "&" + keyword;
- // クッキーのセット
- DBTREE::board_set_list_cookies_for_write( m_url, list_cookies );
-
// subbbs.cgi にポスト先を変更してもう一回ポスト
m_subbbs = true;
++m_count; // 永久ループ防止
@@ -451,13 +443,10 @@ void Post::receive_finish()
#ifdef _DEBUG
std::cout << "Error" << std::endl;
- std::cout << m_errmsg << std::endl;
+ std::cout << m_return_html << std::endl;
#endif
- // クッキー関係のエラーの時はクッキーをセット
- if( tag_2ch.find( "cookie" ) != std::string::npos ) DBTREE::board_set_list_cookies_for_write( m_url, list_cookies );
-
- MISC::ERRMSG( m_return_html );
+ MISC::ERRMSG( m_errmsg );
set_code( HTTP_ERR );
emit_sigfin();
diff --git a/src/message/toolbar.cpp b/src/message/toolbar.cpp
index 365b38c5..fa9cc977 100644
--- a/src/message/toolbar.cpp
+++ b/src/message/toolbar.cpp
@@ -84,6 +84,9 @@ MessageToolBar::MessageToolBar() :
}
+MessageToolBar::~MessageToolBar() noexcept = default;
+
+
// 新規スレ名entry表示切り替え
void MessageToolBar::show_entry_new_subject( bool show )
{
@@ -236,6 +239,8 @@ MessageToolBarPreview::MessageToolBarPreview() :
}
+MessageToolBarPreview::~MessageToolBarPreview() noexcept = default;
+
// ボタンのパッキング
// virtual
diff --git a/src/message/toolbar.h b/src/message/toolbar.h
index 624a6942..dbd3a7ad 100644
--- a/src/message/toolbar.h
+++ b/src/message/toolbar.h
@@ -28,7 +28,7 @@ namespace MESSAGE
public:
MessageToolBarBase();
- ~MessageToolBarBase() noexcept {}
+ ~MessageToolBarBase() noexcept = default;
// previewボタンのトグル
void set_active_previewbutton( const bool active );
@@ -59,7 +59,7 @@ namespace MESSAGE
public:
MessageToolBar();
- ~MessageToolBar() noexcept {}
+ ~MessageToolBar() noexcept;
void show_entry_new_subject( bool show );
std::string get_new_subject();
@@ -83,7 +83,7 @@ namespace MESSAGE
public:
MessageToolBarPreview();
- ~MessageToolBarPreview() noexcept {}
+ ~MessageToolBarPreview() noexcept;
protected:
diff --git a/src/msgitempref.h b/src/msgitempref.h
index 03b218d8..82066bb4 100644
--- a/src/msgitempref.h
+++ b/src/msgitempref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
MsgItemPref( Gtk::Window* parent, const std::string& url );
- ~MsgItemPref() noexcept {}
+ ~MsgItemPref() noexcept = default;
private:
diff --git a/src/openurldiag.h b/src/openurldiag.h
index 63fcfb8d..22a05236 100644
--- a/src/openurldiag.h
+++ b/src/openurldiag.h
@@ -19,7 +19,7 @@ namespace CORE
public:
OpenURLDialog( const std::string& url );
- ~OpenURLDialog() noexcept {}
+ ~OpenURLDialog() noexcept = default;
protected:
diff --git a/src/passwdpref.h b/src/passwdpref.h
index 657668b6..205c4081 100644
--- a/src/passwdpref.h
+++ b/src/passwdpref.h
@@ -33,7 +33,7 @@ namespace CORE
PasswdFrame2ch()
: m_label_sid_2ch( false, "SID: ", CORE::get_login2ch()->get_sessionid() ),
- entry_id( true, "ユーザID(_I): " ), entry_passwd( true, "秘密鍵(_P): " )
+ entry_id( true, "ユーザID(_I): " ), entry_passwd( true, "パスワード(_P): " )
{
const int mrg = 8;
@@ -176,7 +176,7 @@ namespace CORE
show_all_children();
}
- ~PasswdPref() noexcept {}
+ ~PasswdPref() noexcept = default;
};
}
diff --git a/src/prefdiagfactory.cpp b/src/prefdiagfactory.cpp
index cc1c5a1b..24cd8c5d 100644
--- a/src/prefdiagfactory.cpp
+++ b/src/prefdiagfactory.cpp
@@ -6,6 +6,7 @@
#include "privacypref.h"
#include "browserpref.h"
#include "linkfilterpref.h"
+#include "replacestrpref.h"
#include "usrcmdpref.h"
#include "proxypref.h"
#include "globalabonepref.h"
@@ -51,6 +52,9 @@ SKELETON::PrefDiag* CORE::PrefDiagFactory( Gtk::Window* parent, const int type,
case PREFDIAG_LINKFILTER:
return new CORE::LinkFilterPref( parent, url );
+ case PREFDIAG_REPLACESTR:
+ return new CORE::ReplaceStrPref( parent, url );
+
case PREFDIAG_USRCMD:
return new CORE::UsrCmdPref( parent, url );
diff --git a/src/prefdiagfactory.h b/src/prefdiagfactory.h
index 7cf4c59d..ebd47e9a 100644
--- a/src/prefdiagfactory.h
+++ b/src/prefdiagfactory.h
@@ -20,6 +20,7 @@ namespace CORE
PREFDIAG_PRIVACY,
PREFDIAG_BROWSER,
PREFDIAG_LINKFILTER,
+ PREFDIAG_REPLACESTR,
PREFDIAG_USRCMD,
PREFDIAG_PROXY,
PREFDIAG_GLOBALABONETHREAD,
diff --git a/src/privacypref.h b/src/privacypref.h
index fcf80bb1..4468a7f3 100644
--- a/src/privacypref.h
+++ b/src/privacypref.h
@@ -78,7 +78,7 @@ namespace CORE
show_all_children();
}
- ~PrivacyPref() noexcept {}
+ ~PrivacyPref() noexcept = default;
};
}
diff --git a/src/proxypref.h b/src/proxypref.h
index 88742c31..1d9be002 100644
--- a/src/proxypref.h
+++ b/src/proxypref.h
@@ -132,7 +132,7 @@ namespace CORE
show_all_children();
}
- ~ProxyPref() noexcept {}
+ ~ProxyPref() noexcept = default;
};
}
diff --git a/src/replacestrmanager.cpp b/src/replacestrmanager.cpp
new file mode 100644
index 00000000..ca09ca29
--- /dev/null
+++ b/src/replacestrmanager.cpp
@@ -0,0 +1,330 @@
+// ライセンス: GPL2
+
+//#define _DEBUG
+#include "jddebug.h"
+
+#include "replacestrmanager.h"
+#include "cache.h"
+#include "type.h"
+#include "command.h"
+
+#include "jdlib/miscmsg.h"
+#include "jdlib/miscutil.h"
+
+#include "xml/document.h"
+#include "xml/tools.h"
+
+#define ROOT_NODE_NAME_REPLACESTR "replacestrlist"
+
+static const char* const target_str[] = { "subject", "name", "mail", "date", "msg" };
+
+
+static CORE::ReplaceStr_Manager* instance_replacestr_manager = NULL;
+
+CORE::ReplaceStr_Manager* CORE::get_replacestr_manager()
+{
+ if( ! instance_replacestr_manager ) instance_replacestr_manager = new ReplaceStr_Manager();
+ assert( instance_replacestr_manager );
+
+ return instance_replacestr_manager;
+}
+
+
+void CORE::delete_replacestr_manager()
+{
+ if( instance_replacestr_manager ) delete instance_replacestr_manager;
+ instance_replacestr_manager = NULL;
+}
+
+///////////////////////////////////////////////
+
+using namespace CORE;
+
+ReplaceStr_Manager::ReplaceStr_Manager()
+{
+ for(int i = 0; i < REPLACETARGET_MAX; ++i ) m_chref[ i ] = false;
+
+ std::string xml;
+ if( CACHE::load_rawdata( CACHE::path_replacestr(), xml ) ) xml2list( xml );
+ else{
+ // デフォルトの設定を行う
+ m_chref[ 0 ] = true;
+ ReplaceStrCondition condition = { { false, false, false, false, false } };
+ list_append( 0, condition.raw, "ダブルクリックすると編集出来ます",
+ "(この項目は削除して構いません)" );
+ condition.flag.regex = true;
+ list_append( 0, condition.raw, "^\\[(無断)?転載禁止\\]",
+ "<span weight=\"heavy\" color=\"darkgreen\">...</span>" );
+ list_append( 0, condition.raw,
+ "(\\[無?断?転載禁止\\]©([25]ch\\.net|bbspink\\.com)|\\[無?断?転載禁止\\]"
+ "|©[25]ch\\.net|©bbspink\\.com)([[:blank:]]+\\[[[:digit:]]+\\])?$",
+ "<span weight=\"heavy\" color=\"darkgreen\">...</span>\\3" );
+ }
+}
+
+
+ReplaceStr_Manager::~ReplaceStr_Manager()
+{
+ for( int i = 0; i < REPLACETARGET_MAX; ++i ) list_clear( i );
+}
+
+
+//
+// リストをクリア
+//
+void ReplaceStr_Manager::list_clear( const int id )
+{
+ ReplaceStrItemList::iterator it = m_list[ id ].begin();
+ for( ; it != m_list[ id ].end(); it++ ) delete *it;
+ m_list[ id ].clear();
+}
+
+
+//
+// アイテムをリストに追加
+//
+void ReplaceStr_Manager::list_append( const int id, const int condition, const std::string& pattern, const std::string& replace )
+{
+ if( id >= REPLACETARGET_MAX ) return;
+
+ ReplaceStrItem* item = new ReplaceStrItem;
+
+ item->condition = condition;
+ item->pattern = pattern;
+ item->replace = replace;
+
+ ReplaceStrCondition* cdt = ( ReplaceStrCondition* )&condition;
+ if( cdt->flag.regex ){
+ const bool newline = true;
+ const bool migemo = true;
+
+ if( ! item->creg.set( pattern, cdt->flag.icase, newline, migemo,
+ cdt->flag.wchar, cdt->flag.norm ) ){
+ std::string msg ="invlid replacestr pattern: ";
+ msg += item->creg.errstr() + ": " + pattern;
+ MISC::ERRMSG( msg );
+ }
+ }
+
+#ifdef _DEBUG
+ std::cout << "conditnon=" << item->condition << " pattern=" << item->pattern
+ << " replace=" << item->replace << std::endl;
+#endif
+
+ m_list[ id ].push_back( item );
+}
+
+
+//
+// xml -> リスト
+//
+void ReplaceStr_Manager::xml2list( const std::string& xml )
+{
+ for( int i = 0; i < REPLACETARGET_MAX; ++i ) list_clear( i );
+ if( xml.empty() ) return;
+
+ XML::Document document( xml );
+
+ XML::Dom* root = document.get_root_element( std::string( ROOT_NODE_NAME_REPLACESTR ) );
+ if( ! root ) return;
+
+ XML::DomList domlist = root->childNodes();
+
+#ifdef _DEBUG
+ std::cout << "ReplaceStr_Manager::xml2list";
+ std::cout << " children =" << document.childNodes().size() << std::endl;
+#endif
+
+ std::list< XML::Dom* >::const_iterator it = domlist.begin();
+ for( ; it != domlist.end(); ++it ){
+
+ if( ( *it )->nodeType() != XML::NODE_TYPE_ELEMENT ) continue;
+
+ const int type = XML::get_type( ( *it )->nodeName() );
+ if( type != TYPE_DIR ) continue;
+
+ const size_t id = target_id( ( *it )->getAttribute( "name" ) );
+ if( id >= REPLACETARGET_MAX ) continue;
+
+ m_chref[ id ] = ( *it )->getAttribute( "chref" ) == "true";
+
+ XML::DomList domlist_query = ( *it )->childNodes();
+ std::list< XML::Dom* >::const_iterator it_query = domlist_query.begin();
+ for( ; it_query != domlist_query.end(); ++it_query ){
+
+ if( ( *it_query )->nodeType() != XML::NODE_TYPE_ELEMENT ) continue;
+
+ const int type = XML::get_type( ( *it_query )->nodeName() );
+ if( type != TYPE_REPLACESTR ) continue;
+
+ list_append( id, atoi( ( *it_query )->getAttribute( "condition" ).c_str() ),
+ ( *it_query )->getAttribute( "pattern" ),
+ ( *it_query )->getAttribute( "replace" ) );
+ }
+ }
+}
+
+
+//
+// XML 保存
+//
+void ReplaceStr_Manager::save_xml()
+{
+ XML::Document document;
+ XML::Dom* root = document.appendChild( XML::NODE_TYPE_ELEMENT, std::string( ROOT_NODE_NAME_REPLACESTR ) );
+ if( ! root ) return;
+
+ for( int i = 0; i < REPLACETARGET_MAX; ++i ){
+
+ if( m_list[ i ].empty() ) continue;
+
+ XML::Dom* node = dom_append( root, i, m_chref[ i ] );
+
+ ReplaceStrItemList::const_iterator it = m_list[ i ].begin();
+ for( ; it != m_list[ i ].end(); ++it ){
+ dom_append( node, ( *it )->condition, ( *it )->pattern, ( *it )->replace );
+ }
+ }
+
+#ifdef _DEBUG
+ std::cout << "ReplaceStr_Manager::save_xml" << std::endl;
+ std::cout << document.get_xml() << std::endl;
+#endif
+
+ CACHE::save_rawdata( CACHE::path_replacestr(), document.get_xml() );
+}
+
+
+//
+// 置換対象の要素名からid取得
+//
+int ReplaceStr_Manager::target_id( const std::string& name )
+{
+ int id;
+
+ for( id = 0; id < REPLACETARGET_MAX; ++id )
+ if( name.compare( 0, std::string::npos, target_str[ id ] ) == 0 ) break;
+
+ return id;
+}
+
+
+//
+// 置換対象idから要素名取得
+//
+std::string ReplaceStr_Manager::target_name( const int id )
+{
+ const char *name;
+
+ if( id >= REPLACETARGET_MAX ) name = NULL;
+ else name = target_str[ id ];
+
+ return std::string( name );
+}
+
+
+//
+// 実行
+//
+std::string ReplaceStr_Manager::replace( const char* str, const int lng, const int id )
+{
+ if( id >= REPLACETARGET_MAX || m_list[ id ].empty() ) return std::string( str, lng );
+
+ std::string str_work;
+
+ if( m_chref[ id ] ) str_work = MISC::chref_decode( str, lng, false );
+ else str_work.assign( str, lng );
+
+#ifdef _DEBUG
+ std::cout << "ReplaceStr_Manager::replace str=" << str_work << std::endl;
+#endif
+
+ JDLIB::Regex regex;
+
+ ReplaceStrItemList::const_iterator it = m_list[ id ].begin();
+ for( ; it != m_list[ id ].end(); ++it ){
+
+ ReplaceStrCondition cdt;
+ cdt.raw = ( *it )->condition;
+
+ if( ! cdt.flag.active || ( *it )->pattern.empty() ) continue;
+
+#ifdef _DEBUG
+ std::cout << "icase=" << cdt.flag.icase << " regex=" << cdt.flag.regex
+ << " wchar=" << cdt.flag.wchar << " norm=" << cdt.flag.norm
+ << " pattern=" << ( *it )->pattern
+ << " replace=" << ( *it )->replace << std::endl;
+#endif
+ if( cdt.flag.regex ){
+ bool match = false;
+ int offset = 0;
+ const int lng_str = str_work.length();
+ std::string str_tmp;
+
+ // 文字列が空の時は"^$"などにマッチするように改行を追加
+ if( lng_str == 0 ) str_work.push_back( '\n' );
+
+ while( regex.match( ( *it )->creg, str_work, offset, match ) ){
+ match = true;
+
+ const int p0 = regex.pos( 0 );
+ if( p0 != offset ) str_tmp += str_work.substr( offset, p0 - offset );
+
+ // \0 ... \9 の文字列を置換
+ str_tmp += regex.replace( ( *it )->replace );
+
+ offset = p0 + regex.str( 0 ).length();
+ if( offset >= lng_str ) break;
+
+ // 0文字にマッチするパターンは繰り返さない
+ if( regex.str( 0 ).length() == 0 ) break;
+ }
+
+ if( match ){
+ if( lng_str > offset )
+ str_work = str_tmp + str_work.substr( offset, lng_str - offset );
+ else
+ str_work = str_tmp;
+ }
+ }
+
+ // 正規表現を使わない置換処理
+ else if( cdt.flag.icase ) str_work = MISC::replace_casestr( str_work, ( *it )->pattern, ( *it )->replace );
+ else str_work = MISC::replace_str( str_work, ( *it )->pattern, ( *it )->replace );
+ }
+
+#ifdef _DEBUG
+ std::cout << "replaced str=" << str_work << std::endl;
+#endif
+
+ return str_work;
+}
+
+
+//
+// 置換対象のXMLノード作成
+//
+XML::Dom* ReplaceStr_Manager::dom_append( XML::Dom* node, const int id, const bool chref )
+{
+ XML::Dom* dir = node->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_DIR ) );
+
+ dir->setAttribute( "name", target_name( id ) );
+ dir->setAttribute( "chref", chref ? "true" : "false" );
+
+ return dir;
+}
+
+
+//
+// 置換条件のXMLノード作成
+//
+XML::Dom* ReplaceStr_Manager::dom_append( XML::Dom* node, const int condition, const std::string& pattern, const std::string& replace )
+{
+ XML::Dom* query = node->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_REPLACESTR ) );
+
+ query->setAttribute( "condition", condition );
+ query->setAttribute( "pattern", pattern );
+ query->setAttribute( "replace", replace );
+
+ return query;
+}
diff --git a/src/replacestrmanager.h b/src/replacestrmanager.h
new file mode 100644
index 00000000..e6b92905
--- /dev/null
+++ b/src/replacestrmanager.h
@@ -0,0 +1,98 @@
+// ライセンス: GPL2
+
+//
+// 文字列置換の管理クラス
+//
+
+#ifndef _REPLACESTRMANAGER_H
+#define _REPLACESTRMANAGER_H
+
+#include <string>
+#include <list>
+
+#include "jdlib/jdregex.h"
+
+namespace XML
+{
+ class Dom;
+}
+
+namespace CORE
+{
+ enum
+ {
+ REPLACETARGET_SUBJECT = 0,
+ REPLACETARGET_NAME,
+ REPLACETARGET_MAIL,
+ REPLACETARGET_DATE,
+ REPLACETARGET_MESSAGE,
+ REPLACETARGET_MAX
+ };
+
+ union ReplaceStrCondition
+ {
+ struct {
+ unsigned int active : 1;
+ unsigned int icase : 1;
+ unsigned int regex : 1;
+ unsigned int wchar : 1;
+ unsigned int norm : 1;
+ unsigned int : 27;
+ } flag;
+ int raw;
+ };
+
+ struct ReplaceStrItem
+ {
+ int condition;
+ std::string pattern;
+ std::string replace;
+ JDLIB::RegexPattern creg;
+ };
+
+ typedef std::list< ReplaceStrItem* > ReplaceStrItemList;
+
+ class ReplaceStr_Manager
+ {
+ ReplaceStrItemList m_list[ REPLACETARGET_MAX ];
+ bool m_chref[ REPLACETARGET_MAX ];
+
+ public:
+
+ ReplaceStr_Manager();
+ ~ReplaceStr_Manager();
+
+ ReplaceStrItemList::const_iterator list_begin( const int id ) const { return m_list[ id ].begin(); }
+ ReplaceStrItemList::const_iterator list_end( const int id ) const { return m_list[ id ].end(); }
+ size_t list_size( const int id ) const { return m_list[ id ].size(); }
+ void list_clear( const int id );
+ void list_append( const int id, const int condition, const std::string& pattern, const std::string& replace );
+
+ bool get_chref( const int id ) const { return m_chref[ id ]; }
+ void set_chref( const int id, const bool chref ){ m_chref[ id ] = chref; }
+
+ void save_xml();
+
+ // 文字列を置換
+ std::string replace( const char* str, const int lng, const int id );
+
+ static XML::Dom* dom_append( XML::Dom* node, const int id, const bool chref );
+ static XML::Dom* dom_append( XML::Dom* node, const int condition, const std::string& pattern, const std::string& replace );
+
+ private:
+
+ void xml2list( const std::string& xml );
+
+ static int target_id( const std::string& name );
+ static std::string target_name( const int id );
+ };
+
+ ///////////////////////////////////////
+ // インターフェース
+
+ ReplaceStr_Manager* get_replacestr_manager();
+ void delete_replacestr_manager();
+}
+
+
+#endif
diff --git a/src/replacestrpref.cpp b/src/replacestrpref.cpp
new file mode 100644
index 00000000..da5d6a96
--- /dev/null
+++ b/src/replacestrpref.cpp
@@ -0,0 +1,517 @@
+// ライセンス: GPL2
+
+//#define _DEBUG
+#include "jddebug.h"
+
+#include "replacestrmanager.h"
+#include "replacestrpref.h"
+
+#include "control/controlid.h"
+#include "jdlib/miscgtk.h"
+#include "jdlib/miscutil.h"
+#include "skeleton/msgdiag.h"
+#include "xml/document.h"
+
+#include "command.h"
+
+using namespace CORE;
+
+ReplaceStrDiag::ReplaceStrDiag( Gtk::Window* parent, const int condition, const std::string& pattern, const std::string& replace )
+ : SKELETON::PrefDiag( parent, "" )
+ , m_button_copy( "この設定をクリップボードにコピー" )
+ , m_check_active( "有効" )
+ , m_check_icase( "大文字小文字" )
+ , m_check_regex( "正規表現" )
+ , m_check_wchar( "全角半角" )
+ , m_check_norm( "互換文字" )
+ , m_entry_pattern( true, "置換パターン:" )
+ , m_entry_replace( true, "置換文字列:" )
+{
+ resize( 600, 1 );
+
+ m_button_copy.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrDiag::slot_copy ) );
+ m_check_regex.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrDiag::slot_sens ) );
+ m_check_wchar.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrDiag::slot_sens ) );
+ m_check_norm.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrDiag::slot_sens ) );
+
+ ReplaceStrCondition cdt;
+ cdt.raw = condition;
+
+ m_check_active.set_active( cdt.flag.active );
+ m_check_icase.set_active( cdt.flag.icase );
+ m_check_regex.set_active( cdt.flag.regex );
+ m_check_wchar.set_active( cdt.flag.wchar );
+ m_check_wchar.set_sensitive( cdt.flag.regex && !cdt.flag.norm );
+ m_check_norm.set_active( cdt.flag.norm );
+ m_check_norm.set_sensitive( cdt.flag.regex && cdt.flag.wchar );
+
+ m_check_active.set_tooltip_text( "この条件の置換を有効にする" );
+ m_check_icase.set_tooltip_text( "大文字小文字を区別しない" );
+ m_check_regex.set_tooltip_text( "正規表現を使用する" );
+ m_check_wchar.set_tooltip_text( "英数字とカナの種類(俗にいう全角半角)を区別しない" );
+ m_check_norm.set_tooltip_text( "Unicodeの互換文字を区別しない" );
+
+ m_hbox_regex.pack_start( m_check_icase, Gtk::PACK_SHRINK );
+ m_hbox_regex.pack_start( m_check_regex, Gtk::PACK_SHRINK );
+ m_hbox_regex.pack_start( m_check_wchar, Gtk::PACK_SHRINK );
+ m_hbox_regex.pack_start( m_check_norm, Gtk::PACK_SHRINK );
+
+ m_entry_pattern.set_text( pattern );
+ m_entry_replace.set_text( replace );
+
+ m_hbox_active.pack_start( m_check_active );
+ m_hbox_active.pack_start( m_button_copy, Gtk::PACK_SHRINK );
+
+ get_vbox()->set_spacing( 8 );
+ get_vbox()->pack_start( m_hbox_active, Gtk::PACK_SHRINK );
+ get_vbox()->pack_start( m_hbox_regex, Gtk::PACK_SHRINK );
+ get_vbox()->pack_start( m_entry_pattern, Gtk::PACK_SHRINK );
+ get_vbox()->pack_start( m_entry_replace, Gtk::PACK_SHRINK );
+
+ set_title( "置換条件設定" );
+ show_all_children();
+}
+
+
+//
+// 条件フラグ取得
+//
+int ReplaceStrDiag::get_condition() const
+{
+ ReplaceStrCondition condition;
+
+ condition.raw = 0;
+ condition.flag.active = get_active();
+ condition.flag.icase = get_icase();
+ condition.flag.regex = get_regex();
+ condition.flag.wchar = get_wchar();
+ condition.flag.norm = get_norm();
+
+ return condition.raw;
+}
+
+
+//
+// クリップボードにコピー
+//
+void ReplaceStrDiag::slot_copy()
+{
+ XML::Document document;
+ XML::Dom* node = ReplaceStr_Manager::dom_append( &document, get_condition(), get_pattern(), get_replace() );
+
+ MISC::CopyClipboard( node->get_xml() );
+}
+
+
+//
+// wcharチェックボックスのsensitive切り替え
+//
+void ReplaceStrDiag::slot_sens()
+{
+ m_check_wchar.set_sensitive( get_regex() && !get_norm() );
+ m_check_norm.set_sensitive( get_regex() && get_wchar() );
+}
+
+
+///////////////////////////////////////////////
+
+static const char * const target_name[ REPLACEPREF_NUM_TARGET ] = {
+ "スレタイトル", "名前", "メール", "日付/ID", "本文" };
+
+ReplaceStrPref::ReplaceStrPref( Gtk::Window* parent, const std::string& url )
+ : SKELETON::PrefDiag( parent, url ),
+ m_id_target( 0 ),
+ m_label_target( "置換対象:" ),
+ m_label_menu( target_name[ 0 ] ),
+ m_menu_target( true, m_label_menu ),
+ m_check_chref( "対象の置換前に文字参照をデコード" ),
+ m_button_top( Gtk::Stock::GOTO_TOP ),
+ m_button_up( Gtk::Stock::GO_UP ),
+ m_button_down( Gtk::Stock::GO_DOWN ),
+ m_button_bottom( Gtk::Stock::GOTO_BOTTOM ),
+ m_button_delete( Gtk::Stock::DELETE ),
+ m_button_add( Gtk::Stock::ADD )
+{
+ m_button_top.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_top ) );
+ m_button_up.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_up ) );
+ m_button_down.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_down ) );
+ m_button_bottom.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_bottom ) );
+ m_button_delete.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_delete ) );
+ m_button_add.signal_clicked().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_add ) );
+
+ for( int i = 0; i < REPLACEPREF_NUM_TARGET; ++i ){
+ m_store[ i ] = Gtk::ListStore::create( m_columns );
+ }
+ m_current_store = m_store[ 0 ];
+ m_treeview.set_model( m_current_store );
+ m_treeview.set_size_request( 640, 400 );
+ m_treeview.signal_row_activated().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_row_activated ) );
+ m_treeview.sig_key_release().connect( sigc::mem_fun(*this, &ReplaceStrPref::slot_key_release ) );
+
+ Gtk::TreeViewColumn* column[ REPLACEPREF_NUM_COLUMNS ];
+
+ column[ 0 ] = Gtk::manage( new Gtk::TreeViewColumn( "有効", m_columns.m_col_active ) );
+ column[ 0 ]->set_fixed_width( 35 );
+ column[ 0 ]->set_alignment( Gtk::ALIGN_CENTER );
+ column[ 1 ] = Gtk::manage( new Gtk::TreeViewColumn( "大小", m_columns.m_col_icase ) );
+ column[ 1 ]->set_fixed_width( 35 );
+ column[ 1 ]->set_alignment( Gtk::ALIGN_CENTER );
+ column[ 2 ] = Gtk::manage( new Gtk::TreeViewColumn( "正規", m_columns.m_col_regex ) );
+ column[ 2 ]->set_fixed_width( 35 );
+ column[ 2 ]->set_alignment( Gtk::ALIGN_CENTER );
+ column[ 3 ] = Gtk::manage( new Gtk::TreeViewColumn( "置換パターン", m_columns.m_col_pattern ) );
+ column[ 3 ]->set_fixed_width( 220 );
+ column[ 4 ] = Gtk::manage( new Gtk::TreeViewColumn( "置換文字列", m_columns.m_col_replace ) );
+ column[ 4 ]->set_fixed_width( 200 );
+
+ for( int i = 0; i < REPLACEPREF_NUM_COLUMNS; ++i ){
+ column[ i ]->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED );
+ column[ i ]->set_resizable( true );
+ m_treeview.append_column( *( column[ i ] ) );
+ }
+
+ m_scrollwin.add( m_treeview );
+ m_scrollwin.set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS );
+ m_scrollwin.set_size_request( 640, 400 );
+
+ m_vbuttonbox.pack_start( m_button_top, Gtk::PACK_SHRINK );
+ m_vbuttonbox.pack_start( m_button_up, Gtk::PACK_SHRINK );
+ m_vbuttonbox.pack_start( m_button_down, Gtk::PACK_SHRINK );
+ m_vbuttonbox.pack_start( m_button_bottom, Gtk::PACK_SHRINK );
+ m_vbuttonbox.pack_start( m_button_delete, Gtk::PACK_SHRINK );
+ m_vbuttonbox.pack_start( m_button_add, Gtk::PACK_SHRINK );
+ m_vbuttonbox.set_layout( Gtk::BUTTONBOX_START );
+ m_vbuttonbox.set_spacing( 4 );
+
+ m_hbox.pack_start( m_scrollwin, Gtk::PACK_EXPAND_WIDGET );
+ m_hbox.pack_start( m_vbuttonbox, Gtk::PACK_SHRINK );
+
+ std::vector< std::string > list_target;
+ for( int i = 0; i < REPLACEPREF_NUM_TARGET; ++i ) list_target.push_back( target_name[ i ] );
+ m_menu_target.append_menu( list_target );
+ m_menu_target.set_enable_sig_clicked( false );
+ m_menu_target.signal_selected().connect( sigc::mem_fun( *this, &ReplaceStrPref::slot_target_changed ) );
+
+ m_hbox_target.set_border_width( 8 );
+ m_hbox_target.set_spacing( 8 );
+ m_hbox_target.pack_start( m_label_target, Gtk::PACK_SHRINK );
+ m_hbox_target.pack_start( m_menu_target, Gtk::PACK_SHRINK );
+
+ m_check_chref.set_tooltip_markup( "ダブルクォーテション<b>\"</b>, アンパサント"
+ "<b>&amp;</b>, 少なり記号<b>&lt;</b>, 大なり記号<b>&gt;</b>を<b>除く</b>"
+ "文字参照をデコードしてから置換を行います。" );
+
+ get_vbox()->set_spacing( 8 );
+ get_vbox()->pack_start( m_hbox_target, Gtk::PACK_SHRINK );
+ get_vbox()->pack_start( m_check_chref, Gtk::PACK_SHRINK );
+ get_vbox()->pack_start( m_hbox );
+
+ show_all_children();
+ set_title( "文字列置換設定" );
+
+ append_rows();
+}
+
+
+void ReplaceStrPref::append_rows()
+{
+ ReplaceStr_Manager* mgr = CORE::get_replacestr_manager();
+
+ for( int i = 0; i < REPLACEPREF_NUM_TARGET; ++i ){
+
+ m_chref[ i ] = mgr->get_chref( i );
+
+ ReplaceStrItemList::const_iterator it = mgr->list_begin( i );
+
+ for( ; it != mgr->list_end( i ); ++it ){
+ append_row( m_store[ i ], ( *it )->condition, ( *it )->pattern, ( *it )->replace );
+ }
+ }
+
+ m_check_chref.set_active( m_chref[ 0 ] );
+ select_row( get_top_row() );
+}
+
+
+void ReplaceStrPref::append_row( Glib::RefPtr< Gtk::ListStore > store, const int condition, const std::string& pattern, const std::string& replace )
+{
+ Gtk::TreeModel::Row row = *( store->append() );
+
+ if( row ){
+ const ReplaceStrCondition* cdt = ( const ReplaceStrCondition * ) &condition;
+
+ row[ m_columns.m_col_active ] = cdt->flag.active;
+ row[ m_columns.m_col_icase ] = cdt->flag.icase;
+ row[ m_columns.m_col_regex ] = cdt->flag.regex;
+ row[ m_columns.m_col_wchar ] = cdt->flag.wchar;
+ row[ m_columns.m_col_norm ] = cdt->flag.norm;
+ row[ m_columns.m_col_pattern ] = pattern;
+ row[ m_columns.m_col_replace ] = replace;
+
+ select_row( row );
+ }
+}
+
+
+Gtk::TreeModel::const_iterator ReplaceStrPref::get_selected_row() const
+{
+ std::vector< Gtk::TreeModel::Path > paths = m_treeview.get_selection()->get_selected_rows();
+
+ if( ! paths.size() ) return Gtk::TreeModel::const_iterator();
+ return *( m_current_store->get_iter( *paths.begin() ) );
+}
+
+
+Gtk::TreeModel::const_iterator ReplaceStrPref::get_top_row() const
+{
+ Gtk::TreeModel::Children children = m_current_store->children();
+
+ if( children.empty() ) return Gtk::TreeModel::const_iterator();
+ return children.begin();
+}
+
+
+Gtk::TreeModel::const_iterator ReplaceStrPref::get_bottom_row() const
+{
+ Gtk::TreeModel::Children children = m_current_store->children();
+
+ if( children.empty() ) return Gtk::TreeModel::const_iterator();
+ return --children.end();
+}
+
+
+void ReplaceStrPref::select_row( const Gtk::TreeModel::const_iterator& it )
+{
+ if( !it ) return;
+
+ const Gtk::TreePath path( it );
+ m_treeview.get_selection()->select( path );
+}
+
+
+//
+// OK ボタンを押した
+//
+void ReplaceStrPref::slot_ok_clicked()
+{
+#ifdef _DEBUG
+ std::cout << "ReplaceStrPref::slot_ok_clicked" << std::endl;
+#endif
+
+ ReplaceStr_Manager* mgr = CORE::get_replacestr_manager();
+
+ m_chref[ m_id_target ] = m_check_chref.get_active();
+
+ for( int i = 0; i < REPLACEPREF_NUM_TARGET; ++i ){
+
+ mgr->list_clear( i );
+
+ mgr->set_chref( i, m_chref[ i ] );
+
+ Gtk::TreeModel::Children children = m_store[ i ]->children();
+ for( Gtk::TreeModel::iterator it = children.begin(); it != children.end(); ++it ){
+
+ Gtk::TreeModel::Row row = ( *it );
+
+ const bool active = row[ m_columns.m_col_active ];
+ const bool icase = row[ m_columns.m_col_icase ];
+ const bool regex = row[ m_columns.m_col_regex ];
+ const bool wchar = row[ m_columns.m_col_wchar ];
+ const bool norm = row[ m_columns.m_col_norm ];
+
+ ReplaceStrCondition cdt = { { active, icase, regex, wchar, norm } };
+ const std::string& pattern = row[ m_columns.m_col_pattern ];
+ const std::string& replace = row[ m_columns.m_col_replace ];
+
+ mgr->list_append( i, cdt.raw, pattern, replace );
+#ifdef _DEBUG
+ std::cout << "target=" << i << " condition=" << cdt.raw
+ << " pattern=" << pattern << " replace=" << replace << std::endl;
+#endif
+ }
+ }
+
+ CORE::get_replacestr_manager()->save_xml();
+
+ //DBTREE::update_abone_thread();
+ CORE::core_set_command( "relayout_all_board" );
+ CORE::core_set_command( "relayout_all_article", "", "completely" );
+}
+
+
+void ReplaceStrPref::slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column )
+{
+#ifdef _DEBUG
+ std::cout << "ReplaceStrPref::slot_row_activated path = " << path.to_string() << std::endl;
+#endif
+
+ Gtk::TreeModel::Row row = *( m_current_store->get_iter( path ) );
+ if( ! row ) return;
+
+ const bool active = row[ m_columns.m_col_active ];
+ const bool icase = row[ m_columns.m_col_icase ];
+ const bool regex = row[ m_columns.m_col_regex ];
+ const bool wchar = row[ m_columns.m_col_wchar ];
+ const bool norm = row[ m_columns.m_col_norm ];
+ ReplaceStrCondition condition = { { active, icase, regex, wchar, norm } };
+
+ ReplaceStrDiag dlg( this, condition.raw, row[ m_columns.m_col_pattern ], row[ m_columns.m_col_replace ] );
+ if( dlg.run() == Gtk::RESPONSE_OK ){
+ row[ m_columns.m_col_active ] = dlg.get_active();
+ row[ m_columns.m_col_icase ] = dlg.get_icase();
+ row[ m_columns.m_col_regex ] = dlg.get_regex();
+ row[ m_columns.m_col_wchar ] = dlg.get_wchar();
+ row[ m_columns.m_col_norm ] = dlg.get_norm();
+ row[ m_columns.m_col_pattern ] = dlg.get_pattern();
+ row[ m_columns.m_col_replace ] = dlg.get_replace();
+
+ if( dlg.get_regex() ){
+ JDLIB::RegexPattern ptn;
+ const bool newline = true;
+ const bool migemo = true;
+
+ if( ! ptn.set( dlg.get_pattern(), dlg.get_icase(), newline, migemo, dlg.get_wchar(), dlg.get_norm() ) ){
+ std::string msg = ptn.errstr() + "\n\n" + dlg.get_pattern();
+
+ SKELETON::MsgDiag mdlg( NULL, msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK );
+ mdlg.run();
+ }
+ }
+ }
+}
+
+
+bool ReplaceStrPref::slot_key_release( GdkEventKey* event )
+{
+ const int id = m_control.key_press( event );
+
+#ifdef _DEBUG
+ std::cout << "ReplaceStrPref::slot_key_release id = " << id << std::endl;
+#endif
+
+ if( id == CONTROL::Delete ) slot_delete();
+
+ return true;
+}
+
+
+//
+// 一番上へ移動
+//
+void ReplaceStrPref::slot_top()
+{
+ Gtk::TreeModel::iterator it = get_selected_row();
+ Gtk::TreeModel::iterator it_top = get_top_row();
+
+ if( it && it != it_top ) m_current_store->move( it, it_top );
+}
+
+
+//
+// 上へ移動
+//
+void ReplaceStrPref::slot_up()
+{
+ Gtk::TreeModel::iterator it = get_selected_row();
+ Gtk::TreeModel::iterator it_top = get_top_row();
+
+ if( it && it != it_top ){
+
+ Gtk::TreePath path_dst( it );
+ if( path_dst.prev() ){
+
+ Gtk::TreeModel::iterator it_dst = m_current_store->get_iter( path_dst );
+ m_current_store->iter_swap( it, it_dst );
+ }
+ }
+}
+
+
+//
+// 下へ移動
+//
+void ReplaceStrPref::slot_down()
+{
+ Gtk::TreeModel::iterator it = get_selected_row();
+ Gtk::TreeModel::iterator it_bottom = get_bottom_row();
+
+ if( it && it != it_bottom ){
+
+ Gtk::TreePath path_dst( it );
+ path_dst.next();
+ Gtk::TreeModel::iterator it_dst = m_current_store->get_iter( path_dst );
+ if( it_dst ) m_current_store->iter_swap( it, it_dst );
+ }
+}
+
+
+
+//
+// 一番下へ移動
+//
+void ReplaceStrPref::slot_bottom()
+{
+ Gtk::TreeModel::iterator it = get_selected_row();
+ Gtk::TreeModel::iterator it_bottom = get_bottom_row();
+
+ if( it && it != it_bottom ){
+ m_current_store->move( it, m_current_store->children().end() );
+ }
+}
+
+
+//
+// 削除ボタン
+//
+void ReplaceStrPref::slot_delete()
+{
+ Gtk::TreeModel::iterator it = get_selected_row();
+ if( ! it ) return;
+
+ SKELETON::MsgDiag mdiag( NULL, "削除しますか?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO );
+ if( mdiag.run() != Gtk::RESPONSE_YES ) return;
+
+ Gtk::TreePath path_next( it );
+ path_next.next();
+ Gtk::TreeModel::iterator it_next = m_current_store->get_iter( path_next );
+
+ m_current_store->erase( it );
+
+ if( it_next ) select_row( it_next );
+ else{
+ Gtk::TreeModel::iterator it_bottom = get_bottom_row();
+ if( it_bottom ) select_row( it_bottom );
+ }
+}
+
+
+//
+// 追加ボタン
+//
+void ReplaceStrPref::slot_add()
+{
+ ReplaceStrCondition condition = { { true, false, false, false, false } };
+ ReplaceStrDiag dlg( this, condition.raw, "", "" );
+ if( dlg.run() == Gtk::RESPONSE_OK )
+ append_row( m_current_store, dlg.get_condition(),
+ dlg.get_pattern(), dlg.get_replace() );
+}
+
+
+//
+// 置換対象変更
+//
+void ReplaceStrPref::slot_target_changed( const int id )
+{
+#ifdef _DEBUG
+ std::cout << "ReplaceStrPref::slot_target_changed target=" << id << std::endl;
+#endif
+
+ m_chref[ m_id_target ] = m_check_chref.get_active();
+ m_check_chref.set_active( m_chref[ id ] );
+ m_label_menu.set_text( target_name[ id ] );
+ m_current_store = m_store[ id ];
+ m_treeview.set_model( m_current_store );
+ select_row( get_top_row() );
+ m_id_target = id;
+}
diff --git a/src/replacestrpref.h b/src/replacestrpref.h
new file mode 100644
index 00000000..21454677
--- /dev/null
+++ b/src/replacestrpref.h
@@ -0,0 +1,140 @@
+// ライセンス: GPL2
+
+// 文字列置換設定ダイアログ
+
+#ifndef _REPLACESTRPREF_H
+#define _REPLACESTRPREF_H
+
+#include "skeleton/label_entry.h"
+#include "skeleton/menubutton.h"
+#include "skeleton/prefdiag.h"
+#include "skeleton/treeviewbase.h"
+
+#include "control/control.h"
+
+namespace CORE
+{
+ class ReplaceStrDiag : public SKELETON::PrefDiag
+ {
+ Gtk::HBox m_hbox_active;
+ Gtk::HBox m_hbox_regex;
+ Gtk::Button m_button_copy;
+ Gtk::CheckButton m_check_active;
+ Gtk::CheckButton m_check_icase;
+ Gtk::CheckButton m_check_regex;
+ Gtk::CheckButton m_check_wchar;
+ Gtk::CheckButton m_check_norm;
+ SKELETON::LabelEntry m_entry_pattern;
+ SKELETON::LabelEntry m_entry_replace;
+
+ public:
+
+ ReplaceStrDiag( Gtk::Window* parent, const int condition, const std::string& pattern, const std::string& replace );
+
+ bool get_active() const { return m_check_active.get_active(); }
+ bool get_icase() const { return m_check_icase.get_active(); }
+ bool get_regex() const { return m_check_regex.get_active(); }
+ bool get_wchar() const { return m_check_wchar.get_active(); }
+ bool get_norm() const { return m_check_norm.get_active(); }
+ int get_condition() const;
+ Glib::ustring get_pattern() const { return m_entry_pattern.get_text(); }
+ Glib::ustring get_replace() const { return m_entry_replace.get_text(); }
+
+ private:
+ void slot_copy();
+ void slot_sens();
+ };
+
+
+ class ReplaceRecord : public Gtk::TreeModel::ColumnRecord
+ {
+ public:
+
+ Gtk::TreeModelColumn< bool > m_col_active;
+ Gtk::TreeModelColumn< bool > m_col_icase;
+ Gtk::TreeModelColumn< bool > m_col_regex;
+ Gtk::TreeModelColumn< bool > m_col_wchar;
+ Gtk::TreeModelColumn< bool > m_col_norm;
+ Gtk::TreeModelColumn< std::string > m_col_pattern;
+ Gtk::TreeModelColumn< std::string > m_col_replace;
+
+ ReplaceRecord()
+ {
+ add( m_col_active );
+ add( m_col_icase );
+ add( m_col_regex );
+ add( m_col_wchar );
+ add( m_col_norm );
+ add( m_col_pattern );
+ add( m_col_replace );
+ }
+ };
+
+ enum{
+ REPLACEPREF_NUM_COLUMNS = 5, // カラム数
+ REPLACEPREF_NUM_TARGET = 5 // タイトル、名前、メール、ID、本文
+ };
+
+
+ class ReplaceStrPref : public SKELETON::PrefDiag
+ {
+ int m_id_target;
+ Gtk::HBox m_hbox_target;
+ Gtk::Label m_label_target;
+ Gtk::Label m_label_menu;
+ SKELETON::MenuButton m_menu_target;
+
+ Gtk::CheckButton m_check_chref;
+ bool m_chref[ REPLACEPREF_NUM_TARGET ];
+
+ SKELETON::JDTreeViewBase m_treeview;
+ CONTROL::Control m_control;
+ Glib::RefPtr< Gtk::ListStore > m_store[ REPLACEPREF_NUM_TARGET ];
+ Glib::RefPtr< Gtk::ListStore > m_current_store;
+ ReplaceRecord m_columns;
+ Gtk::ScrolledWindow m_scrollwin;
+
+ Gtk::Button m_button_top;
+ Gtk::Button m_button_up;
+ Gtk::Button m_button_down;
+ Gtk::Button m_button_bottom;
+ Gtk::Button m_button_delete;
+ Gtk::Button m_button_add;
+ Gtk::VButtonBox m_vbuttonbox;
+
+ Gtk::HBox m_hbox;
+
+ public:
+
+ ReplaceStrPref( Gtk::Window* parent, const std::string& url );
+
+ private:
+
+ void append_rows();
+ void append_row( Glib::RefPtr< Gtk::ListStore > store, const int condition,
+ const std::string& pattern, const std::string& replace );
+
+ Gtk::TreeModel::const_iterator get_selected_row() const;
+ Gtk::TreeModel::const_iterator get_top_row() const;
+ Gtk::TreeModel::const_iterator get_bottom_row() const;
+
+ void select_row( const Gtk::TreeModel::const_iterator& it );
+
+ // OK押した
+ virtual void slot_ok_clicked();
+
+ void slot_row_activated( const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column );
+ bool slot_key_release( GdkEventKey* event );
+
+ void slot_top();
+ void slot_up();
+ void slot_down();
+ void slot_bottom();
+ void slot_delete();
+ void slot_add();
+
+ void slot_target_changed( const int id );
+ };
+}
+
+#endif
diff --git a/src/searchitempref.h b/src/searchitempref.h
index e13b0cf8..b073aaa4 100644
--- a/src/searchitempref.h
+++ b/src/searchitempref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
SearchItemPref( Gtk::Window* parent, const std::string& url );
- ~SearchItemPref() noexcept {}
+ ~SearchItemPref() noexcept = default;
private:
diff --git a/src/searchloader.cpp b/src/searchloader.cpp
index 1bcac8cc..bd61e067 100644
--- a/src/searchloader.cpp
+++ b/src/searchloader.cpp
@@ -3,11 +3,11 @@
//#define _DEBUG
#include "jddebug.h"
+#include "charcode.h"
#include "searchloader.h"
#include "usrcmdmanager.h"
#include "jdlib/loaderdata.h"
-#include "jdlib/miscutil.h"
#include "config/globalconf.h"
@@ -19,19 +19,21 @@ SearchLoader::SearchLoader()
{
std::string url = CONFIG::get_url_search_title();
- m_charset = "UTF-8";
+ CharCode charcode = CHARCODE_UTF8;
// 結果のエンコード指定を、検索結果のエンコードに設定する
- if( url.find( "$OUTU" ) != std::string::npos ) m_charset = "UTF-8";
- else if( url.find( "$OUTX" ) != std::string::npos ) m_charset = "EUC-JP";
- else if( url.find( "$OUTE" ) != std::string::npos ) m_charset = "MS932";
+ if( url.find( "$OUTU" ) != std::string::npos ) charcode = CHARCODE_UTF8;
+ else if( url.find( "$OUTX" ) != std::string::npos ) charcode = CHARCODE_EUCJP;
+ else if( url.find( "$OUTE" ) != std::string::npos ) charcode = CHARCODE_SJIS;
// 結果のエンコード指定がない場合は、検索クエリのエンコードを検索結果のエンコードに設定する
- else if( url.find( "$TEXTX" ) != std::string::npos ) m_charset = "EUC-JP";
- else if( url.find( "$TEXTE" ) != std::string::npos ) m_charset = "MS932";
+ else if( url.find( "$TEXTX" ) != std::string::npos ) charcode = CHARCODE_EUCJP;
+ else if( url.find( "$TEXTE" ) != std::string::npos ) charcode = CHARCODE_SJIS;
+
+ set_charcode( charcode );
#ifdef _DEBUG
- std::cout << "SearchLoader::SearchLoader charset = " << m_charset << std::endl;;
+ std::cout << "SearchLoader::SearchLoader charcode = " << charcode << std::endl;;
#endif
}
@@ -64,7 +66,7 @@ void SearchLoader::search( const std::string& query )
m_query = query;
reset();
- download_text();
+ download_text( get_charcode() );
}
diff --git a/src/searchloader.h b/src/searchloader.h
index bf764b8a..81c78296 100644
--- a/src/searchloader.h
+++ b/src/searchloader.h
@@ -19,7 +19,6 @@ namespace CORE
SIG_SEARCH_FIN m_sig_search_fin;
- std::string m_charset;
std::string m_query;
public:
@@ -35,7 +34,6 @@ namespace CORE
std::string get_url() override;
std::string get_path() override { return {}; }
- std::string get_charset() override { return m_charset; }
// ロード用データ作成
void create_loaderdata( JDLIB::LOADERDATA& data ) override;
diff --git a/src/searchmanager.cpp b/src/searchmanager.cpp
index 3c8730f3..53c8f076 100644
--- a/src/searchmanager.cpp
+++ b/src/searchmanager.cpp
@@ -262,7 +262,7 @@ void Search_Manager::search_fin_title()
const bool newline = true;
const bool usemigemo = false;
const bool wchar = false;
- regex.compile( CONFIG::get_regex_search_title(), icase, newline, usemigemo, wchar );
+ JDLIB::RegexPattern regexptn( CONFIG::get_regex_search_title(), icase, newline, usemigemo, wchar );
std::list< std::string > lines = MISC::get_lines( m_searchloader->get_data() );
std::list< std::string >::iterator it;
@@ -272,15 +272,26 @@ void Search_Manager::search_fin_title()
if( line.empty() ) continue;
- // & が &amp; に置き換わっているので直す
- if( line.find( "&" ) != std::string::npos ) line = MISC::replace_str( line, "&amp;", "&" );
-
offset = 0;
- while( regex.exec( line, offset ) ){
+ while( regex.match( regexptn, line, offset ) ){
SEARCHDATA data;
- data.url_readcgi = DBTREE::url_readcgi( regex.str( 1 ), 0, 0 );
- data.subject = MISC::html_unescape( regex.str( 2 ) );
+
+ // びんたんのURLだったら変換する
+ // http://bintan.ula.cc/test/read.cgi/server.2ch.net/board/0000000000/l50
+ if( !regex.str( 1 ).compare( 0, 21, "http://bintan.ula.cc/" ) ){
+ size_t pos = regex.str( 1 ).find_first_of( '/', 35 );
+ if( pos != std::string::npos )
+ data.url_readcgi = regex.str( 1 ).substr( 0, 7 )
+ + regex.str( 1 ).substr( 35, pos - 35 )
+ + regex.str( 1 ).substr( 20, 14 )
+ + regex.str( 1 ).substr( pos, std::string::npos );
+ }
+ else{
+ data.url_readcgi = DBTREE::url_readcgi( regex.str( 1 ), 0, 0 );
+ }
+
+ data.subject = regex.str( 2 );
data.num = atoi( regex.str( 3 ).c_str() );
data.bookmarked = false;
data.num_bookmarked = 0;
diff --git a/src/sidebaritempref.h b/src/sidebaritempref.h
index 211a61ab..6248eb1e 100644
--- a/src/sidebaritempref.h
+++ b/src/sidebaritempref.h
@@ -14,7 +14,7 @@ namespace CORE
public:
SidebarItemPref( Gtk::Window* parent, const std::string& url );
- ~SidebarItemPref() noexcept {}
+ ~SidebarItemPref() noexcept = default;
private:
diff --git a/src/skeleton/Makefile.am b/src/skeleton/Makefile.am
index a996f11b..23093cd6 100644
--- a/src/skeleton/Makefile.am
+++ b/src/skeleton/Makefile.am
@@ -26,6 +26,7 @@ libskeleton_a_SOURCES = \
menubutton.cpp \
toolmenubutton.cpp \
backforwardbutton.cpp \
+ popupwinbase.cpp \
popupwin.cpp \
tooltip.cpp \
entry.cpp \
@@ -88,6 +89,7 @@ noinst_HEADERS = \
msgdiag.h \
aboutdiag.h \
detaildiag.h \
+ editviewdialog.h \
filediag.h \
login.h \
panecontrol.h \
diff --git a/src/skeleton/aboutdiag.cpp b/src/skeleton/aboutdiag.cpp
index df3f22b1..aae3809b 100644
--- a/src/skeleton/aboutdiag.cpp
+++ b/src/skeleton/aboutdiag.cpp
@@ -43,6 +43,9 @@ AboutDiag::AboutDiag( const Glib::ustring& title )
}
+AboutDiag::~AboutDiag() noexcept = default;
+
+
//
// run()
//
@@ -311,6 +314,10 @@ void AboutDiag::set_environment_list()
row[ column_name ] = "glibmmのバージョン";
row[ column_value ] = ENVIRONMENT::get_glibmm_version();
+ row = *( liststore->append() );
+ row[ column_name ] = "TLSライブラリ";
+ row[ column_value ] = ENVIRONMENT::get_tlslib_version();
+
row = *( liststore->append() );
row[ column_name ] = "主なオプション";
row[ column_value ] = ENVIRONMENT::get_configure_args( ENVIRONMENT::CONFIGURE_OMITTED );
diff --git a/src/skeleton/aboutdiag.h b/src/skeleton/aboutdiag.h
index e121781b..154d33fb 100644
--- a/src/skeleton/aboutdiag.h
+++ b/src/skeleton/aboutdiag.h
@@ -49,8 +49,7 @@ namespace SKELETON
public:
AboutDiag( const Glib::ustring& title );
-
- ~AboutDiag(){}
+ ~AboutDiag() noexcept;
int run();
diff --git a/src/skeleton/admin.cpp b/src/skeleton/admin.cpp
index cd254161..51aef09d 100644
--- a/src/skeleton/admin.cpp
+++ b/src/skeleton/admin.cpp
@@ -631,7 +631,10 @@ void Admin::exec_command()
}
// 全てのビューを再描画
- else if( command.command == "relayout_all" ) relayout_all();
+ else if( command.command == "relayout_all" ){
+ const bool completely = ( command.arg1 == "completely" );
+ relayout_all( completely );
+ }
// タイトル表示
// アクティブなviewから依頼が来たらコアに渡す
@@ -1821,11 +1824,12 @@ void Admin::set_tablabel( const std::string& url, const std::string& str_label )
SKELETON::View* view = get_view( url );
if( view ){
- m_notebook->set_tab_fulltext( str_label, m_notebook->page_num( *view ) );
+ std::string label = MISC::to_plain( str_label );
+ m_notebook->set_tab_fulltext( label, m_notebook->page_num( *view ) );
// View履歴のタイトルも更新
if( m_use_viewhistory ){
- HISTORY::get_history_manager()->replace_current_title_viewhistory( view->get_url(), str_label );
+ HISTORY::get_history_manager()->replace_current_title_viewhistory( view->get_url(), label );
}
}
}
@@ -1835,13 +1839,13 @@ void Admin::set_tablabel( const std::string& url, const std::string& str_label )
//
// 再レイアウト実行
//
-void Admin::relayout_all()
+void Admin::relayout_all( const bool completely )
{
std::list< SKELETON::View* > list_view = get_list_view();
std::list< SKELETON::View* >::iterator it = list_view.begin();
for( ; it != list_view.end(); ++it ){
SKELETON::View* view = ( *it );
- if( view ) view->relayout();
+ if( view ) view->relayout( completely );
}
}
diff --git a/src/skeleton/admin.h b/src/skeleton/admin.h
index 7f9a825a..e0edaad5 100644
--- a/src/skeleton/admin.h
+++ b/src/skeleton/admin.h
@@ -205,7 +205,6 @@ namespace SKELETON
virtual void update_item( const std::string& url, const std::string& id );
virtual void update_finish( const std::string& url );
virtual void close_view( const std::string& url );
- virtual void close_view( View* view );
virtual void unlock_all_view( const std::string& url );
virtual void close_all_view( const std::string& url );
virtual void close_other_views( const std::string& url );
@@ -220,7 +219,7 @@ namespace SKELETON
virtual void restore_focus();
virtual void focus_out();
virtual void set_tablabel( const std::string& url, const std::string& str_label );
- virtual void relayout_all();
+ virtual void relayout_all( const bool completely = false );
virtual void open_window(){}
virtual void close_window(){}
virtual void toggle_tab();
@@ -345,6 +344,8 @@ namespace SKELETON
void append_switchhistory( const std::string& url );
void remove_switchhistory( const std::string& url );
std::string get_valid_switchhistory();
+
+ void close_view( View* view );
};
}
diff --git a/src/skeleton/compentry.cpp b/src/skeleton/compentry.cpp
index 83ae5187..52149ac5 100644
--- a/src/skeleton/compentry.cpp
+++ b/src/skeleton/compentry.cpp
@@ -56,8 +56,7 @@ CompletionEntry::CompletionEntry( const int mode )
}
-CompletionEntry::~CompletionEntry() noexcept
-{}
+CompletionEntry::~CompletionEntry() noexcept = default;
// 補完実行
diff --git a/src/skeleton/dragnote.cpp b/src/skeleton/dragnote.cpp
index ca217ee7..6928b4ad 100644
--- a/src/skeleton/dragnote.cpp
+++ b/src/skeleton/dragnote.cpp
@@ -259,19 +259,21 @@ void DragableNoteBook::set_show_tabs( bool show_tabs )
std::cout << "DragableNoteBook::set_show_tabs show_tabs = " << show_tabs << std::endl;
#endif
- if( m_show_tabs ){
+ if( ! show_tabs && m_show_tabs ){
remove( m_hbox_tab );
m_show_tabs = false;
}
- else{
+ else if( show_tabs && ! m_show_tabs ){
- remove( m_notebook_toolbar );
+ if( m_show_toolbar && m_notebook_toolbar.get_n_pages() )
+ remove( m_notebook_toolbar );
remove( m_notebook_view );
pack_start( m_hbox_tab, Gtk::PACK_SHRINK );
- pack_start( m_notebook_toolbar, Gtk::PACK_SHRINK );
+ if( m_show_toolbar && m_notebook_toolbar.get_n_pages() )
+ pack_start( m_notebook_toolbar, Gtk::PACK_SHRINK );
pack_start( m_notebook_view );
m_show_tabs = true;
diff --git a/src/skeleton/dragtreeview.cpp b/src/skeleton/dragtreeview.cpp
index f9c503e7..f31a1bd4 100644
--- a/src/skeleton/dragtreeview.cpp
+++ b/src/skeleton/dragtreeview.cpp
@@ -195,42 +195,6 @@ void DragTreeView::clock_in()
}
-//
-// ツールチップに文字をセット
-//
-void DragTreeView::set_str_tooltip( const std::string& text )
-{
- m_tooltip.set_text( text );
-}
-
-
-//
-// ツールチップ最小幅設定
-//
-void DragTreeView::set_tooltip_min_width( const int min_width )
-{
- m_tooltip.set_min_width( min_width);
-}
-
-
-//
-// ツールチップを表示
-//
-void DragTreeView::show_tooltip()
-{
- m_tooltip.show_tooltip();
-}
-
-
-//
-// ツールチップ隠す
-//
-void DragTreeView::hide_tooltip()
-{
- m_tooltip.hide_tooltip();
-}
-
-
//
// ポップアップが表示されていてかつマウスがその上にあるか
//
diff --git a/src/skeleton/dragtreeview.h b/src/skeleton/dragtreeview.h
index 7d9f76ad..1a09059a 100644
--- a/src/skeleton/dragtreeview.h
+++ b/src/skeleton/dragtreeview.h
@@ -90,12 +90,13 @@ namespace SKELETON
// フォント初期化
void init_font( const std::string& fontname );
- // ツールチップ表示
- // set_tooltip_min_width()で指定した幅よりもツールチップが広い場合は表示
- void set_str_tooltip( const std::string& str );
- void set_tooltip_min_width( const int min_width );
- void hide_tooltip();
- void show_tooltip();
+ // ツールチップに文字をセット
+ void set_str_tooltip( const std::string& str, const bool use_markup = false ){
+ if( use_markup ) m_tooltip.set_markup( str ); else m_tooltip.set_text( str ); }
+ // ツールチップ最小幅設定(指定した幅よりもツールチップが広い場合は表示)
+ void set_tooltip_min_width( const int& min_width ){ m_tooltip.set_min_width( min_width ); }
+ void hide_tooltip(){ m_tooltip.hide_tooltip(); }
+ void show_tooltip(){ m_tooltip.show_tooltip(); }
// ポップアップウィンドウ表示
const std::string& pre_popup_url() const { return m_pre_popup_url; }
diff --git a/src/skeleton/editview.cpp b/src/skeleton/editview.cpp
index 8bc18b5b..fac3fc67 100644
--- a/src/skeleton/editview.cpp
+++ b/src/skeleton/editview.cpp
@@ -483,8 +483,8 @@ void EditTextView::on_populate_popup( Gtk::Menu* menu )
menuitem->signal_activate().connect( sigc::mem_fun( *this, &EditTextView::slot_write_jdinfo ) );
menu->prepend( *menuitem );
- // 変換(スペース⇔&nbsp;)
- menuitem = Gtk::manage( new Gtk::MenuItem( "変換(スペース⇔&nbsp;)" ) );
+ // 変換(スペース⇔&#160;)
+ menuitem = Gtk::manage( new Gtk::MenuItem( "変換(スペース⇔&#160;)" ) );
menuitem->signal_activate().connect( sigc::mem_fun( *this, &EditTextView::slot_convert_space ) );
menu->prepend( *menuitem );
@@ -540,7 +540,7 @@ void EditTextView::slot_quote_clipboard()
//
-// 変換(スペース⇔&nbsp;)
+// 変換(スペース⇔&#160;)
//
void EditTextView::slot_convert_space()
{
@@ -550,32 +550,38 @@ void EditTextView::slot_convert_space()
std::string text = buffer->get_text();
std::string converted;
- // &nbsp;が含まれていたらスペースに変換する
- if( text.find( "&nbsp;", 0 ) != std::string::npos )
+ // &#160;が含まれていたらスペースに変換する
+ if( text.find( "&#160;", 0 ) != std::string::npos )
{
- converted = MISC::replace_str( text, "&nbsp;", " " );
+ converted = MISC::replace_str( text, "&#160;", " " );
}
else
{
- size_t rpos = std::string::npos;
- size_t nlpos = std::string::npos;
+ std::list< std::string > list = MISC::get_lines( text );
+ for( std::list< std::string >::iterator it = list.begin(); it != list.end(); ++it ){
- // 改行前のスペースを取り除く
- while( ( nlpos = text.rfind( "\n", rpos ) ) != std::string::npos )
- {
- if( nlpos == 0 ) break;
- rpos = nlpos;
- while( text[ rpos - 1 ] == ' ' ) rpos--;
- text.erase( rpos, nlpos - rpos );
- rpos--;
+ size_t rpos = it->length();
+ if( rpos != 0 ){
+
+ // 行末のスペースを取り除く
+ while( it->compare( rpos - 1, 1, " " ) == 0 ) rpos--;
+ it->erase( rpos, std::string::npos );
+
+ // 行頭のスペースを&#160;に変換する
+ if( it->compare( 0, 1, " " ) == 0 ){
+ it->erase( 0, 1 );
+ it->insert( 0, "&#160;" );
+ }
+
+ // 連続スペースを&#160;に変換する
+ converted += MISC::replace_str( *it, " ", " &#160;" );
+ }
+
+ converted.push_back( '\n' );
}
- // 最後のスペースを取り除く
- rpos = text.length();
- while( text[ rpos - 1 ] == ' ' ) rpos--;
- text.erase( rpos, std::string::npos );
-
- converted = MISC::replace_str( text, " ", "&nbsp;" );
+ // 最後の改行を取り除く
+ converted.erase( converted.length() - 1, std::string::npos );
}
buffer->set_text( converted );
@@ -718,6 +724,24 @@ void EditTextView::slot_hide_aamenu()
}
+//////////////////////////////////////////////
+
+EditView::EditView()
+ : Gtk::ScrolledWindow()
+{
+ set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
+ add( m_textview );
+#if GTKMM_CHECK_VERSION(3,0,0)
+ auto context = m_textview.get_style_context();
+ context->add_class( s_css_classname );
+ context->add_provider( m_provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION );
+#endif
+ show_all_children();
+}
+
+
+EditView::~EditView() noexcept = default;
+
#if GTKMM_CHECK_VERSION(3,0,0)
constexpr const char* EditView::s_css_classname;
diff --git a/src/skeleton/editview.h b/src/skeleton/editview.h
index f957e675..d7e42a0b 100644
--- a/src/skeleton/editview.h
+++ b/src/skeleton/editview.h
@@ -8,7 +8,7 @@
#include <gtkmm.h>
#include "control/control.h"
-#include "jdlib/miscutil.h"
+#include "jdlib/misccharcode.h"
namespace SKELETON
{
@@ -130,19 +130,8 @@ namespace SKELETON
public:
- EditView(){
- set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
-
- add( m_textview );
-#if GTKMM_CHECK_VERSION(3,0,0)
- auto context = m_textview.get_style_context();
- context->add_class( s_css_classname );
- context->add_provider( m_provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION );
-#endif
-
- show_all_children();
- }
- ~EditView() noexcept {}
+ EditView();
+ ~EditView() noexcept;
SIG_BUTTON_PRESS sig_button_press(){ return m_textview.sig_button_press(); }
SIG_KEY_PRESS sig_key_press(){ return m_textview.sig_key_press(); }
diff --git a/src/skeleton/entry.cpp b/src/skeleton/entry.cpp
index 646401da..cd837805 100644
--- a/src/skeleton/entry.cpp
+++ b/src/skeleton/entry.cpp
@@ -16,6 +16,14 @@
using namespace SKELETON;
+JDEntry::JDEntry()
+ : Gtk::Entry()
+{}
+
+
+JDEntry::~JDEntry() noexcept = default;
+
+
// ボタン入力のフック
bool JDEntry::on_button_press_event( GdkEventButton* event )
{
diff --git a/src/skeleton/entry.h b/src/skeleton/entry.h
index c2923059..27477a1a 100644
--- a/src/skeleton/entry.h
+++ b/src/skeleton/entry.h
@@ -32,8 +32,8 @@ namespace SKELETON
SIG_KEY_PRESS signal_key_press(){ return m_sig_key_press; }
SIG_OPERATE signal_operate(){ return m_sig_operate; }
- JDEntry() : Gtk::Entry(){}
- ~JDEntry() noexcept {}
+ JDEntry();
+ ~JDEntry() noexcept;
// CONTROL::Control のモード設定( controlid.h 参照 )
// キー入力をフックして JDEntry::on_key_release_event() で SIG_OPERATE をemitする
diff --git a/src/skeleton/filediag.h b/src/skeleton/filediag.h
index 226f407b..f515fc1d 100644
--- a/src/skeleton/filediag.h
+++ b/src/skeleton/filediag.h
@@ -45,7 +45,7 @@ namespace SKELETON
else set_transient_for( *CORE::get_mainwindow() );
}
- ~FileDiag() noexcept {}
+ ~FileDiag() noexcept = default;
virtual int run(){
diff --git a/src/skeleton/hpaned.cpp b/src/skeleton/hpaned.cpp
index 84148eda..9fa66318 100644
--- a/src/skeleton/hpaned.cpp
+++ b/src/skeleton/hpaned.cpp
@@ -14,6 +14,9 @@ JDHPaned::JDHPaned( const int fixmode )
{}
+JDHPaned::~JDHPaned() noexcept = default;
+
+
void JDHPaned::on_realize()
{
Gtk::HPaned::on_realize();
diff --git a/src/skeleton/hpaned.h b/src/skeleton/hpaned.h
index c3448696..bd2f5598 100644
--- a/src/skeleton/hpaned.h
+++ b/src/skeleton/hpaned.h
@@ -19,7 +19,7 @@ namespace SKELETON
public:
JDHPaned( const int fixmode );
- ~JDHPaned() noexcept {}
+ ~JDHPaned() noexcept;
HPaneControl& get_ctrl(){ return m_pctrl; }
diff --git a/src/skeleton/imgbutton.cpp b/src/skeleton/imgbutton.cpp
index 56a79b33..2808f998 100644
--- a/src/skeleton/imgbutton.cpp
+++ b/src/skeleton/imgbutton.cpp
@@ -24,6 +24,9 @@ ImgButton::ImgButton( const Gtk::StockID& stock_id, const std::string label,
}
+ImgButton::~ImgButton() noexcept = default;
+
+
void ImgButton::set( const std::string& label )
{
if( ! m_img ) return;
diff --git a/src/skeleton/imgbutton.h b/src/skeleton/imgbutton.h
index 895a14a0..ba39f681 100644
--- a/src/skeleton/imgbutton.h
+++ b/src/skeleton/imgbutton.h
@@ -23,6 +23,9 @@ namespace SKELETON
ImgButton( const Gtk::StockID& stock_id,
const std::string label = std::string(),
const Gtk::BuiltinIconSize icon_size = Gtk::ICON_SIZE_MENU );
+
+ ~ImgButton() noexcept;
+
private:
void set( const std::string& label );
diff --git a/src/skeleton/imgtoggletoolbutton.cpp b/src/skeleton/imgtoggletoolbutton.cpp
index 264b225b..1d91159d 100644
--- a/src/skeleton/imgtoggletoolbutton.cpp
+++ b/src/skeleton/imgtoggletoolbutton.cpp
@@ -14,3 +14,6 @@ ImgToggleToolButton::ImgToggleToolButton( const int id )
m_img = Gtk::manage( new Gtk::Image( ICON::get_icon( id ) ) );
set_icon_widget( *m_img );
}
+
+
+ImgToggleToolButton::~ImgToggleToolButton() noexcept = default;
diff --git a/src/skeleton/imgtoggletoolbutton.h b/src/skeleton/imgtoggletoolbutton.h
index 27ccf1d0..d234f261 100644
--- a/src/skeleton/imgtoggletoolbutton.h
+++ b/src/skeleton/imgtoggletoolbutton.h
@@ -17,6 +17,7 @@ namespace SKELETON
public:
ImgToggleToolButton( const int id );
+ ~ImgToggleToolButton() noexcept;
};
}
diff --git a/src/skeleton/imgtoolbutton.cpp b/src/skeleton/imgtoolbutton.cpp
index 50b2549f..e287ba9f 100644
--- a/src/skeleton/imgtoolbutton.cpp
+++ b/src/skeleton/imgtoolbutton.cpp
@@ -16,3 +16,6 @@ ImgToolButton::ImgToolButton( const int id )
m_img = Gtk::manage( new Gtk::Image( ICON::get_icon( id ) ) );
set_icon_widget( *m_img );
}
+
+
+ImgToolButton::~ImgToolButton() noexcept = default;
diff --git a/src/skeleton/imgtoolbutton.h b/src/skeleton/imgtoolbutton.h
index 8121a92a..8af69da5 100644
--- a/src/skeleton/imgtoolbutton.h
+++ b/src/skeleton/imgtoolbutton.h
@@ -17,6 +17,7 @@ namespace SKELETON
public:
ImgToolButton( const int id );
+ ~ImgToolButton() noexcept;
};
}
diff --git a/src/skeleton/jdtoolbar.cpp b/src/skeleton/jdtoolbar.cpp
index 3615735b..d282d6fc 100644
--- a/src/skeleton/jdtoolbar.cpp
+++ b/src/skeleton/jdtoolbar.cpp
@@ -178,10 +178,26 @@ customized_gtk_toolbar_expose (GtkWidget *widget,
///////////////////////////////////////////////////
+#endif // !GTKMM_CHECK_VERSION(3,0,0)
+
using namespace SKELETON;
+JDToolbar::JDToolbar()
+{
+#if GTKMM_CHECK_VERSION(3,0,0)
+ // 子ウィジェットの配色がGTKテーマと違うことがある。
+ // ツールバーのcssクラスを削除し配色を修正する。
+ get_style_context()->remove_class( GTK_STYLE_CLASS_TOOLBAR );
+#endif
+}
+
+
+JDToolbar::~JDToolbar() noexcept = default;
+
+
+#if !GTKMM_CHECK_VERSION(3,0,0)
bool JDToolbar::on_expose_event( GdkEventExpose* event )
{
#ifdef _DEBUG
@@ -199,5 +215,4 @@ bool JDToolbar::on_expose_event( GdkEventExpose* event )
return FALSE;
}
-
#endif // !GTKMM_CHECK_VERSION(3,0,0)
diff --git a/src/skeleton/jdtoolbar.h b/src/skeleton/jdtoolbar.h
index baa13d88..e3739892 100644
--- a/src/skeleton/jdtoolbar.h
+++ b/src/skeleton/jdtoolbar.h
@@ -15,14 +15,8 @@ namespace SKELETON
class JDToolbar : public Gtk::Toolbar
{
public:
- JDToolbar()
- {
-#if GTKMM_CHECK_VERSION(3,0,0)
- // 子ウィジェットの配色がGTKテーマと違うことがある。
- // ツールバーのcssクラスを削除し配色を修正する。
- get_style_context()->remove_class( GTK_STYLE_CLASS_TOOLBAR );
-#endif
- }
+ JDToolbar();
+ ~JDToolbar() noexcept;
// GTK+3ではデフォルトの描画処理に任せる
#if !GTKMM_CHECK_VERSION(3,0,0)
diff --git a/src/skeleton/label_entry.cpp b/src/skeleton/label_entry.cpp
index c56f76e8..3d8a4344 100644
--- a/src/skeleton/label_entry.cpp
+++ b/src/skeleton/label_entry.cpp
@@ -26,6 +26,9 @@ LabelEntry::LabelEntry( const bool editable, const std::string& label, const std
}
+LabelEntry::~LabelEntry() noexcept = default;
+
+
void LabelEntry::setup()
{
if( m_editable ) pack_start( m_entry );
diff --git a/src/skeleton/label_entry.h b/src/skeleton/label_entry.h
index 52bab447..ad88905b 100644
--- a/src/skeleton/label_entry.h
+++ b/src/skeleton/label_entry.h
@@ -27,6 +27,7 @@ namespace SKELETON
public:
LabelEntry( const bool editable, const std::string& label, const std::string& text = std::string() );
+ ~LabelEntry() noexcept;
SIG_ACTIVATE signal_activate(){ return m_sig_activate; }
diff --git a/src/skeleton/loadable.cpp b/src/skeleton/loadable.cpp
index 842acbd1..2b2ec372 100644
--- a/src/skeleton/loadable.cpp
+++ b/src/skeleton/loadable.cpp
@@ -7,6 +7,7 @@
#include "jdlib/loader.h"
#include "jdlib/misctime.h"
+#include "jdlib/miscutil.h"
#include "httpcode.h"
@@ -14,7 +15,8 @@ using namespace SKELETON;
Loadable::Loadable()
: m_loader( NULL ),
- m_low_priority( false )
+ m_low_priority( false ),
+ m_charcode( CHARCODE_UNKNOWN )
{
clear_load_data();
}
@@ -51,6 +53,7 @@ void Loadable::clear_load_data()
m_date_modified = std::string();
m_cookies.clear();
m_location = std::string();
+ m_error = std::string();
m_total_length = 0;
m_current_length = 0;
}
@@ -114,6 +117,7 @@ bool Loadable::start_load( const JDLIB::LOADERDATA& data )
m_code = HTTP_INIT;
m_str_code = std::string();
m_location = std::string();
+ m_error = std::string();
m_total_length = 0;
m_current_length = 0;
@@ -147,6 +151,9 @@ void Loadable::receive( const char* data, size_t size )
if( ! m_total_length && m_code != HTTP_INIT ) m_total_length = get_loader_length();
m_current_length += size;
+ const CharCode charcode = get_loader_content_charset();
+ if( charcode != CHARCODE_UNKNOWN ) set_charcode( charcode );
+
receive_data( data, size );
}
@@ -180,6 +187,10 @@ void Loadable::callback_dispatch()
if( ! get_loader_modified().empty() ) m_date_modified = get_loader_modified();
if( ! get_loader_cookies().empty() ) m_cookies = get_loader_cookies();
if( ! get_loader_location().empty() ) m_location = get_loader_location();
+ if( ! get_loader_error().empty() ) m_error = get_loader_error();
+
+ const CharCode charcode = get_loader_content_charset();
+ if( charcode != CHARCODE_UNKNOWN ) set_charcode( charcode );
#ifdef _DEBUG
std::cout << "delete_loader\n";
@@ -195,6 +206,7 @@ void Loadable::callback_dispatch()
std::cout << "location = " << m_location << std::endl;
std::cout << "total_length = " << m_total_length << std::endl;
std::cout << "current length = " << m_current_length << std::endl;
+ std::cout << "charset = " << get_charcode() << std::endl;
#endif
receive_finish();
@@ -204,7 +216,7 @@ void Loadable::callback_dispatch()
// ローダから各種情報の取得
-int Loadable::get_loader_code()
+int Loadable::get_loader_code() const
{
if( ! m_loader ) return HTTP_INIT;
@@ -212,7 +224,7 @@ int Loadable::get_loader_code()
}
-std::string Loadable::get_loader_str_code()
+std::string Loadable::get_loader_str_code() const
{
if( ! m_loader ) return std::string();
@@ -220,7 +232,7 @@ std::string Loadable::get_loader_str_code()
}
-std::string Loadable::get_loader_contenttype()
+std::string Loadable::get_loader_contenttype() const
{
if( ! m_loader ) return std::string();
@@ -228,7 +240,7 @@ std::string Loadable::get_loader_contenttype()
}
-std::string Loadable::get_loader_modified()
+std::string Loadable::get_loader_modified() const
{
if( ! m_loader ) return std::string();
@@ -236,7 +248,7 @@ std::string Loadable::get_loader_modified()
}
-std::list< std::string > Loadable::get_loader_cookies()
+std::list< std::string > Loadable::get_loader_cookies() const
{
if( ! m_loader ) return std::list< std::string >();
@@ -244,7 +256,7 @@ std::list< std::string > Loadable::get_loader_cookies()
}
-std::string Loadable::get_loader_location()
+std::string Loadable::get_loader_location() const
{
if( ! m_loader ) return std::string();
@@ -252,9 +264,38 @@ std::string Loadable::get_loader_location()
}
-size_t Loadable::get_loader_length()
+size_t Loadable::get_loader_length() const
{
if( ! m_loader ) return 0;
return m_loader->data().length;
}
+
+std::string Loadable::get_loader_error() const
+{
+ if( ! m_loader ) return std::string();
+
+ return m_loader->data().error;
+}
+
+
+CharCode Loadable::get_loader_content_charset() const
+{
+ CharCode charcode = CHARCODE_UNKNOWN;
+
+ if( m_loader ){
+ std::string contenttype = m_loader->data().contenttype;
+ size_t pos = contenttype.find( "charset=" );
+ if( pos != std::string::npos ){
+ std::string raw_charset = MISC::toupper_str( MISC::remove_space( contenttype.substr( pos + 8, std::string::npos ) ) );
+ std::string tmp_charset = MISC::remove_str( MISC::remove_str( raw_charset, "_" ), "-" );
+ if( tmp_charset == "UTF8" ) charcode = CHARCODE_UTF8;
+ else if( tmp_charset == "SHIFTJIS" || tmp_charset == "XSJIS"
+ || tmp_charset == "WINDOWS31J" ) charcode = CHARCODE_SJIS;
+ else if( tmp_charset == "EUCJP" || tmp_charset == "XEUCJP" ) charcode = CHARCODE_EUCJP;
+ // else charset = "iso-8859-1"; // その他は無視する
+ }
+ }
+
+ return charcode;
+}
diff --git a/src/skeleton/loadable.h b/src/skeleton/loadable.h
index 1d6b45c5..73f44265 100644
--- a/src/skeleton/loadable.h
+++ b/src/skeleton/loadable.h
@@ -44,6 +44,7 @@
#ifndef _LOADABLE_H
#define _LOADABLE_H
+#include "charcode.h"
#include "dispatchable.h"
#include <gtkmm.h>
@@ -65,6 +66,8 @@ namespace SKELETON
bool m_low_priority;
+ CharCode m_charcode;
+
// ローダからコピーしたデータ
int m_code;
std::string m_str_code;
@@ -72,6 +75,7 @@ namespace SKELETON
std::string m_date_modified;
std::list< std::string > m_cookies;
std::string m_location;
+ std::string m_error;
size_t m_total_length;
size_t m_current_length;
@@ -86,6 +90,9 @@ namespace SKELETON
// ロード中かどうか
bool is_loading() const;
+ CharCode get_charcode() const { return m_charcode; }
+ void set_charcode( const CharCode charcode ){ m_charcode = charcode; }
+
int get_code() const { return m_code; }
void set_code( int code ) { m_code = code; }
@@ -97,6 +104,8 @@ namespace SKELETON
const std::list< std::string >& cookies() { return m_cookies; }
const std::string& location() const { return m_location; }
+ const std::string& get_error() const { return m_error; }
+
size_t total_length() const { return m_total_length; }
void set_total_length( int length ){ m_total_length = length; }
@@ -141,13 +150,15 @@ namespace SKELETON
void delete_loader();
void callback_dispatch() override;
- int get_loader_code();
- std::string get_loader_str_code();
- std::string get_loader_contenttype();
- std::string get_loader_modified();
- std::list< std::string > get_loader_cookies();
- std::string get_loader_location();
- size_t get_loader_length();
+ int get_loader_code() const;
+ std::string get_loader_str_code() const;
+ std::string get_loader_contenttype() const;
+ std::string get_loader_modified() const;
+ std::list< std::string > get_loader_cookies() const;
+ std::string get_loader_location() const;
+ size_t get_loader_length() const;
+ std::string get_loader_error() const;
+ CharCode get_loader_content_charset() const;
};
}
diff --git a/src/skeleton/lockable.h b/src/skeleton/lockable.h
index 48155a05..9285cb1a 100644
--- a/src/skeleton/lockable.h
+++ b/src/skeleton/lockable.h
@@ -20,7 +20,7 @@ namespace SKELETON
Lockable() :m_lock( 0 ){}
- virtual ~Lockable() noexcept {}
+ virtual ~Lockable() noexcept = default;
int get_lock() const { return m_lock; }
diff --git a/src/skeleton/menubutton.cpp b/src/skeleton/menubutton.cpp
index 76a77da9..0c77852c 100644
--- a/src/skeleton/menubutton.cpp
+++ b/src/skeleton/menubutton.cpp
@@ -181,13 +181,10 @@ void MenuButton::on_clicked()
//
void MenuButton::slot_popup_pos( int& x, int& y, bool& push_in )
{
- const int mrg = 16;
-
- get_pointer( x, y );
int ox, oy;
get_window()->get_origin( ox, oy );
Gdk::Rectangle rect = get_allocation();
- x += ox + rect.get_x() - mrg;
+ x = ox + rect.get_x();
y = oy + rect.get_y() + rect.get_height();
push_in = false;
}
diff --git a/src/skeleton/msgdiag.cpp b/src/skeleton/msgdiag.cpp
index d6faba9c..a04eb737 100644
--- a/src/skeleton/msgdiag.cpp
+++ b/src/skeleton/msgdiag.cpp
@@ -56,6 +56,9 @@ MsgDiag::MsgDiag( Gtk::Window* parent,
}
+MsgDiag::~MsgDiag() noexcept = default;
+
+
void MsgDiag::add_default_button( const Gtk::StockID& stock_id, const int id )
{
Gtk::Button* button = Gtk::manage( new Gtk::Button( stock_id ) );
@@ -203,6 +206,8 @@ MsgCheckDiag::MsgCheckDiag( Gtk::Window* parent,
}
+MsgCheckDiag::~MsgCheckDiag() noexcept = default;
+
/////////////////////////////////////
@@ -218,3 +223,6 @@ MsgOverwriteDiag::MsgOverwriteDiag( Gtk::Window* parent )
add_button( "すべていいえ", OVERWRITE_NO_ALL );
add_button( "すべて上書き", OVERWRITE_YES_ALL );
}
+
+
+MsgOverwriteDiag::~MsgOverwriteDiag() noexcept = default;
diff --git a/src/skeleton/msgdiag.h b/src/skeleton/msgdiag.h
index 032a4fbc..d9bb860e 100644
--- a/src/skeleton/msgdiag.h
+++ b/src/skeleton/msgdiag.h
@@ -33,7 +33,7 @@ namespace SKELETON
Gtk::ButtonsType buttons = Gtk::BUTTONS_OK,
bool modal = false);
- ~MsgDiag() noexcept {}
+ ~MsgDiag() noexcept;
void add_default_button( const Gtk::StockID& stock_id, const int id );
void add_default_button( const Glib::ustring& label, const int id );
@@ -67,6 +67,7 @@ namespace SKELETON
Gtk::ButtonsType buttons = Gtk::BUTTONS_OK,
const int default_response = -1
);
+ ~MsgCheckDiag() noexcept;
Gtk::CheckButton& get_chkbutton(){ return m_chkbutton; }
};
@@ -88,6 +89,7 @@ namespace SKELETON
public:
MsgOverwriteDiag( Gtk::Window* parent );
+ ~MsgOverwriteDiag() noexcept;
};
}
diff --git a/src/skeleton/panecontrol.cpp b/src/skeleton/panecontrol.cpp
index c87838fc..79d26876 100644
--- a/src/skeleton/panecontrol.cpp
+++ b/src/skeleton/panecontrol.cpp
@@ -25,8 +25,7 @@ PaneControl::PaneControl( Gtk::Paned& paned, int fixmode )
}
-PaneControl::~PaneControl() noexcept
-{}
+PaneControl::~PaneControl() noexcept = default;
//
diff --git a/src/skeleton/panecontrol.h b/src/skeleton/panecontrol.h
index 481bfebf..aa812e71 100644
--- a/src/skeleton/panecontrol.h
+++ b/src/skeleton/panecontrol.h
@@ -100,7 +100,7 @@ namespace SKELETON
public:
HPaneControl( Gtk::Paned& paned, int fixmode ) : PaneControl( paned, fixmode ) {}
- ~HPaneControl() noexcept {}
+ ~HPaneControl() noexcept = default;
protected:
@@ -122,7 +122,7 @@ namespace SKELETON
public:
VPaneControl( Gtk::Paned& paned, int fixmode ) : PaneControl( paned, fixmode ) {}
- ~VPaneControl() noexcept {}
+ ~VPaneControl() noexcept = default;
protected:
diff --git a/src/skeleton/popupwinbase.cpp b/src/skeleton/popupwinbase.cpp
new file mode 100644
index 00000000..3c4230ea
--- /dev/null
+++ b/src/skeleton/popupwinbase.cpp
@@ -0,0 +1,81 @@
+// ライセンス: GPL2
+
+//#define _DEBUG
+#include "jddebug.h"
+
+#include "popupwinbase.h"
+
+#if GTKMM_CHECK_VERSION(3,0,0)
+#include "command.h"
+#endif
+
+
+using namespace SKELETON;
+
+
+PopupWinBase::PopupWinBase( bool draw_frame )
+ : Gtk::Window( Gtk::WINDOW_POPUP )
+ , m_draw_frame( draw_frame )
+{
+#ifdef _DEBUG
+ std::cout << "PopupWinBase::PopupWinBase\n";
+#endif
+
+ if( m_draw_frame ) set_border_width( 1 );
+#if GTKMM_CHECK_VERSION(3,0,0)
+ if ( auto main_window = CORE::get_mainwindow() ) {
+ set_transient_for( *main_window );
+ }
+#endif
+}
+
+
+PopupWinBase::~PopupWinBase() noexcept = default;
+
+
+void PopupWinBase::on_realize()
+{
+ Gtk::Window::on_realize();
+
+#if !GTKMM_CHECK_VERSION(3,0,0)
+ Glib::RefPtr< Gdk::Window > window = get_window();
+ m_gc = Gdk::GC::create( window );
+#endif
+}
+
+
+#if GTKMM_CHECK_VERSION(3,0,0)
+bool PopupWinBase::on_draw( const Cairo::RefPtr< Cairo::Context >& cr )
+{
+ const bool ret = Gtk::Window::on_draw( cr );
+ if( m_draw_frame ) {
+ Gdk::Cairo::set_source_rgba( cr, Gdk::RGBA( "black" ) );
+ cr->set_line_width( 1.0 );
+ cr->rectangle( 0.0, 0.0, get_width(), get_height() );
+ cr->stroke();
+ }
+ return ret;
+}
+#else
+bool PopupWinBase::on_expose_event( GdkEventExpose* event )
+{
+ bool ret = Gtk::Window::on_expose_event( event );
+
+ // 枠の描画
+ if( m_draw_frame ){
+ m_gc->set_foreground( Gdk::Color( "black" ) );
+ get_window()->draw_rectangle( m_gc, false, 0, 0, get_width()-1, get_height()-1 );
+ }
+
+ return ret;
+}
+#endif // GTKMM_CHECK_VERSION(3,0,0)
+
+
+bool PopupWinBase::on_configure_event( GdkEventConfigure* event )
+{
+ bool ret = Gtk::Window::on_configure_event( event );
+ m_sig_configured.emit( get_width(), get_height() );
+
+ return ret;
+}
diff --git a/src/skeleton/popupwinbase.h b/src/skeleton/popupwinbase.h
index 17064ec4..701a102b 100644
--- a/src/skeleton/popupwinbase.h
+++ b/src/skeleton/popupwinbase.h
@@ -11,10 +11,6 @@
#include <gtkmm.h>
-#if GTKMM_CHECK_VERSION(3,0,0)
-#include "command.h"
-#endif
-
namespace SKELETON
{
enum
@@ -41,65 +37,20 @@ namespace SKELETON
public:
// draw_frame == true なら枠を描画する
- PopupWinBase( bool draw_frame ) : Gtk::Window( Gtk::WINDOW_POPUP ), m_draw_frame( draw_frame ){
- if( m_draw_frame ) set_border_width( 1 );
-
-#if GTKMM_CHECK_VERSION(3,0,0)
- if ( auto main_window = CORE::get_mainwindow() ) {
- set_transient_for( *main_window );
- }
-#endif
- }
- ~PopupWinBase() noexcept {}
+ PopupWinBase( bool draw_frame );
+ ~PopupWinBase() noexcept;
SIG_CONFIGURED_POPUP sig_configured(){ return m_sig_configured; }
protected:
- void on_realize() override
- {
- Gtk::Window::on_realize();
-
-#if !GTKMM_CHECK_VERSION(3,0,0)
- Glib::RefPtr< Gdk::Window > window = get_window();
- m_gc = Gdk::GC::create( window );
-#endif
- }
-
+ void on_realize() override;
#if GTKMM_CHECK_VERSION(3,0,0)
- bool on_draw( const Cairo::RefPtr< Cairo::Context >& cr ) override
- {
- const bool ret = Gtk::Window::on_draw( cr );
- if( m_draw_frame ) {
- Gdk::Cairo::set_source_rgba( cr, Gdk::RGBA( "black" ) );
- cr->set_line_width( 1.0 );
- cr->rectangle( 0.0, 0.0, get_width(), get_height() );
- cr->stroke();
- }
- return ret;
- }
+ bool on_draw( const Cairo::RefPtr< Cairo::Context >& cr ) override;
#else
- bool on_expose_event( GdkEventExpose* event ) override
- {
- bool ret = Gtk::Window::on_expose_event( event );
-
- // 枠の描画
- if( m_draw_frame ){
- m_gc->set_foreground( Gdk::Color( "black" ) );
- get_window()->draw_rectangle( m_gc, false, 0, 0, get_width()-1, get_height()-1 );
- }
-
- return ret;
- }
-#endif // GTKMM_CHECK_VERSION(3,0,0)
-
- bool on_configure_event( GdkEventConfigure* event ) override
- {
- bool ret = Gtk::Window::on_configure_event( event );
- m_sig_configured.emit( get_width(), get_height() );
-
- return ret;
- }
+ bool on_expose_event( GdkEventExpose* event ) override;
+#endif
+ bool on_configure_event( GdkEventConfigure* event ) override;
};
}
diff --git a/src/skeleton/selectitempref.h b/src/skeleton/selectitempref.h
index 07b5a401..9ce5a8f7 100644
--- a/src/skeleton/selectitempref.h
+++ b/src/skeleton/selectitempref.h
@@ -80,7 +80,7 @@ namespace SKELETON
public:
SelectItemPref( Gtk::Window* parent, const std::string& url );
- ~SelectItemPref() noexcept {}
+ ~SelectItemPref() noexcept = default;
private:
diff --git a/src/skeleton/tabnote.cpp b/src/skeleton/tabnote.cpp
index 5fe10ecc..237a319b 100644
--- a/src/skeleton/tabnote.cpp
+++ b/src/skeleton/tabnote.cpp
@@ -354,7 +354,7 @@ public:
set_flags( Gtk::NO_WINDOW );
#endif
}
- ~DummyWidget() noexcept {}
+ ~DummyWidget() noexcept = default;
};
@@ -404,6 +404,10 @@ TabNotebook::TabNotebook( DragableNoteBook* parent )
m_pre_width = get_width();
}
+
+TabNotebook::~TabNotebook() noexcept = default;
+
+
//
// クロック入力
//
diff --git a/src/skeleton/tabnote.h b/src/skeleton/tabnote.h
index cb5ed138..be8c50e5 100644
--- a/src/skeleton/tabnote.h
+++ b/src/skeleton/tabnote.h
@@ -72,6 +72,7 @@ namespace SKELETON
SIG_SCROLL_EVENT sig_scroll_event(){ return m_sig_scroll_event; }
TabNotebook( DragableNoteBook* parent );
+ ~TabNotebook() noexcept;
void clock_in();
diff --git a/src/skeleton/tabswitchbutton.cpp b/src/skeleton/tabswitchbutton.cpp
index 89ac69c6..dfd1a6ec 100644
--- a/src/skeleton/tabswitchbutton.cpp
+++ b/src/skeleton/tabswitchbutton.cpp
@@ -41,8 +41,7 @@ TabSwitchButton::TabSwitchButton( DragableNoteBook* parent )
}
-TabSwitchButton::~TabSwitchButton() noexcept
-{}
+TabSwitchButton::~TabSwitchButton() noexcept = default;
void TabSwitchButton::show_button()
diff --git a/src/skeleton/textloader.cpp b/src/skeleton/textloader.cpp
index 8e9f8487..6b17342d 100644
--- a/src/skeleton/textloader.cpp
+++ b/src/skeleton/textloader.cpp
@@ -17,7 +17,7 @@
enum
{
- SIZE_OF_RAWDATA = 1024 * 1024
+ SIZE_OF_RAWDATA = 256 * 1024
};
using namespace SKELETON;
@@ -70,12 +70,13 @@ void TextLoader::reset()
//
// キャッシュからロード
//
-void TextLoader::load_text()
+void TextLoader::load_text( const CharCode charcode )
{
if( get_path().empty() ) return;
init();
set_code( HTTP_INIT );
+ set_charcode( charcode );
receive_finish();
}
@@ -83,7 +84,7 @@ void TextLoader::load_text()
//
// ダウンロード開始
//
-void TextLoader::download_text()
+void TextLoader::download_text( const CharCode charcode )
{
#ifdef _DEBUG
std::cout << "TextLoader::download_text url = " << get_url() << std::endl;
@@ -92,7 +93,7 @@ void TextLoader::download_text()
if( is_loading() ) return;
if( m_loaded ) return; // 読み込み済み
if( ! SESSION::is_online() ){
- load_text();
+ load_text( charcode );
return;
}
@@ -103,6 +104,7 @@ void TextLoader::download_text()
JDLIB::LOADERDATA data;
init();
+ set_charcode( charcode );
create_loaderdata( data );
if( data.url.empty() ) return;
if( ! start_load( data ) ) clear();
@@ -173,7 +175,7 @@ void TextLoader::receive_finish()
set_str_code( std::string() );
// UTF-8に変換しておく
- JDLIB::Iconv* libiconv = new JDLIB::Iconv( get_charset(), "UTF-8" );
+ JDLIB::Iconv* libiconv = new JDLIB::Iconv( get_charcode(), CHARCODE_UTF8 );
int byte_out;
m_data = libiconv->convert( m_rawdata , m_lng_rawdata, byte_out );
delete libiconv;
diff --git a/src/skeleton/textloader.h b/src/skeleton/textloader.h
index b918fa2c..05417f5e 100644
--- a/src/skeleton/textloader.h
+++ b/src/skeleton/textloader.h
@@ -9,6 +9,7 @@
#ifndef _TEXTLODER_H
#define _TEXTLODER_H
+#include "charcode.h"
#include "loadable.h"
#include <string>
@@ -39,17 +40,16 @@ namespace SKELETON
void reset();
// キャッシュからロード
- void load_text();
+ void load_text( const CharCode charcode );
// ダウンロード開始
// not modifiedの時はキャッシュから読み込む
- void download_text();
+ void download_text( const CharCode charcode );
protected:
virtual std::string get_url() = 0;
virtual std::string get_path() = 0;
- virtual std::string get_charset() = 0;
// ロード用データ作成
virtual void create_loaderdata( JDLIB::LOADERDATA& data ) = 0;
diff --git a/src/skeleton/toolbar.cpp b/src/skeleton/toolbar.cpp
index a62393cc..8100a044 100644
--- a/src/skeleton/toolbar.cpp
+++ b/src/skeleton/toolbar.cpp
@@ -92,6 +92,9 @@ ToolBar::ToolBar( Admin* admin )
}
+ToolBar::~ToolBar() noexcept = default;
+
+
void ToolBar::set_url( const std::string& url )
{
m_url = url;
@@ -121,8 +124,15 @@ void ToolBar::set_view( SKELETON::View* view )
set_url( view->get_url() );
// ラベル表示更新
- set_label( view->get_label() );
- if( view->is_broken() || view->is_old() || view->is_overflow() ) set_color( view->get_color() );
+ set_label( view->get_label(), view->get_label_use_markup() );
+ if( m_tool_label ){
+ if( view->get_tooltip_label().empty() )
+ set_tooltip( *m_tool_label, view->get_label(), view->get_label_use_markup() );
+ else
+ set_tooltip( *m_tool_label, view->get_tooltip_label(), view->get_label_use_markup() );
+ }
+ if( CONFIG::get_change_statitle_color() && ( view->is_broken() || view->is_old() ) )
+ set_color( view->get_color() );
// 閉じるボタンの表示更新
if( m_button_close ){
@@ -289,12 +299,13 @@ void ToolBar::pack_transparent_separator()
//
// ツールチップ
//
-void ToolBar::set_tooltip( Gtk::ToolItem& toolitem, const std::string& tip )
+void ToolBar::set_tooltip( Gtk::ToolItem& toolitem, const std::string& tip, const bool use_markup )
{
#if GTKMM_CHECK_VERSION(2,12,0)
- toolitem.set_tooltip_text( tip );
+ if( use_markup ) toolitem.set_tooltip_markup( tip );
+ else toolitem.set_tooltip_text( tip );
#else
- toolitem.set_tooltip( m_tooltip, tip );
+ toolitem.set_tooltip( m_tooltip, MISC::html_toplain( tip ) );
#endif
}
@@ -336,12 +347,12 @@ Gtk::ToolItem* ToolBar::get_label()
}
-void ToolBar::set_label( const std::string& label )
+void ToolBar::set_label( const std::string& label, const bool use_markup )
{
if( ! m_ebox_label ) return;
m_label->set_text( label );
- if( m_tool_label ) set_tooltip( *m_tool_label, label );
+ m_label->set_use_markup( use_markup );
set_color( "" );
}
@@ -693,7 +704,7 @@ void ToolBar::slot_open_board()
{
if( ! m_enable_slot ) return;
- CORE::core_set_command( "open_board", DBTREE::url_subject( get_url() ), "true",
+ CORE::core_set_command( "open_board", DBTREE::url_boardbase( get_url() ), "true",
"auto" // オートモードで開く
);
}
@@ -707,9 +718,9 @@ void ToolBar::slot_menu_board( int i )
// ToolBar::get_button_board()で作成したメニューの順番に内容を合わせる
if( i == 0 ) slot_open_board();
- else if( i == 1 ) CORE::core_set_command( "open_board", DBTREE::url_subject( get_url() ), "true" );
- else if( i == 3 ) pref = CORE::PrefDiagFactory( CORE::get_mainwindow(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( get_url() ), "show_localrule" );
- else if( i == 4 ) pref = CORE::PrefDiagFactory( CORE::get_mainwindow(), CORE::PREFDIAG_BOARD, DBTREE::url_subject( get_url() ) );
+ else if( i == 1 ) CORE::core_set_command( "open_board", DBTREE::url_boardbase( get_url() ), "true" );
+ else if( i == 3 ) pref = CORE::PrefDiagFactory( CORE::get_mainwindow(), CORE::PREFDIAG_BOARD, DBTREE::url_boardbase( get_url() ), "show_localrule" );
+ else if( i == 4 ) pref = CORE::PrefDiagFactory( CORE::get_mainwindow(), CORE::PREFDIAG_BOARD, DBTREE::url_boardbase( get_url() ) );
if( pref ){
pref->run();
diff --git a/src/skeleton/toolbar.h b/src/skeleton/toolbar.h
index 3d625395..e8972d07 100644
--- a/src/skeleton/toolbar.h
+++ b/src/skeleton/toolbar.h
@@ -83,7 +83,7 @@ namespace SKELETON
public:
ToolBar( Admin* admin );
- ~ToolBar() noexcept {}
+ ~ToolBar() noexcept;
void set_url( const std::string& url );
const std::string& get_url() { return m_url; }
@@ -173,12 +173,12 @@ namespace SKELETON
void pack_separator();
void pack_transparent_separator();
- void set_tooltip( Gtk::ToolItem& toolitem, const std::string& tip );
+ void set_tooltip( Gtk::ToolItem& toolitem, const std::string& tip, const bool use_markup = false );
private:
// ラベル関係
- void set_label( const std::string& label );
+ void set_label( const std::string& label, const bool use_markup = false );
void set_color( const std::string& color );
// 書き込みボタン関係
diff --git a/src/skeleton/toolbarnote.cpp b/src/skeleton/toolbarnote.cpp
index aba6290e..a23ac54f 100644
--- a/src/skeleton/toolbarnote.cpp
+++ b/src/skeleton/toolbarnote.cpp
@@ -35,6 +35,9 @@ ToolBarNotebook::ToolBarNotebook( DragableNoteBook* parent )
}
+ToolBarNotebook::~ToolBarNotebook() noexcept = default;
+
+
//
// 描画イベント
//
diff --git a/src/skeleton/toolbarnote.h b/src/skeleton/toolbarnote.h
index 96df350d..4a71583e 100644
--- a/src/skeleton/toolbarnote.h
+++ b/src/skeleton/toolbarnote.h
@@ -21,6 +21,7 @@ namespace SKELETON
public:
ToolBarNotebook( DragableNoteBook* parent );
+ ~ToolBarNotebook() noexcept;
#if !GTKMM_CHECK_VERSION(3,0,0)
protected:
diff --git a/src/skeleton/toolmenubutton.cpp b/src/skeleton/toolmenubutton.cpp
index 39b0f38a..ba5af1ac 100644
--- a/src/skeleton/toolmenubutton.cpp
+++ b/src/skeleton/toolmenubutton.cpp
@@ -9,6 +9,9 @@
using namespace SKELETON;
+ToolMenuButton::ToolMenuButton() = default;
+
+
ToolMenuButton::ToolMenuButton( const std::string& label, const bool expand,
const bool show_arrow, Gtk::Widget& widget )
{
@@ -26,6 +29,9 @@ ToolMenuButton::ToolMenuButton( const std::string& label, const bool expand,
}
+ToolMenuButton::~ToolMenuButton() noexcept = default;
+
+
void ToolMenuButton::setup( SKELETON::MenuButton* button, const std::string& label, const bool expand )
{
m_button = button;
diff --git a/src/skeleton/toolmenubutton.h b/src/skeleton/toolmenubutton.h
index a8202b69..ac96d0bb 100644
--- a/src/skeleton/toolmenubutton.h
+++ b/src/skeleton/toolmenubutton.h
@@ -17,11 +17,11 @@ namespace SKELETON
class ToolMenuButton : public Gtk::ToolItem
{
- SKELETON::MenuButton* m_button;
+ SKELETON::MenuButton* m_button = nullptr;
public:
- ToolMenuButton() : m_button( NULL ){}
+ ToolMenuButton();
ToolMenuButton( const std::string& label, const bool expand,
const bool show_arrow,
@@ -31,6 +31,8 @@ namespace SKELETON
const bool show_arrow ,
const int id );
+ ~ToolMenuButton() noexcept;
+
SKELETON::MenuButton* get_button(){ return m_button; }
protected:
diff --git a/src/skeleton/tooltip.cpp b/src/skeleton/tooltip.cpp
index 95298a30..42b8ea57 100644
--- a/src/skeleton/tooltip.cpp
+++ b/src/skeleton/tooltip.cpp
@@ -23,6 +23,9 @@ Tooltip::Tooltip()
}
+Tooltip::~Tooltip() noexcept = default;
+
+
// フォント
void Tooltip::modify_font_label( const std::string& fontname )
{
@@ -50,19 +53,38 @@ void Tooltip::clock_in()
}
-
-
+//
+// ラベル文字列
+//
void Tooltip::set_text( const std::string& text )
{
- if( m_label.get_text() == text ) return;
+ if( m_label.get_label() == text ) return;
#ifdef _DEBUG
- std::cout << "Tooltip::set_text" << text << std::endl;
+ std::cout << "Tooltip::set_text " << text << std::endl;
#endif
hide_tooltip();
resize( 1, 1 );
- m_label.set_text( text );
+ if( text.length() > 5000 ) m_label.set_text( text.substr( 0, 5000 ) );
+ else m_label.set_text( text );
+ m_counter = 0;
+}
+
+
+
+void Tooltip::set_markup( const std::string& text )
+{
+ if( m_label.get_label() == text ) return;
+
+#ifdef _DEBUG
+ std::cout << "Tooltip::set_markup " << text << std::endl;
+#endif
+
+ hide_tooltip();
+ resize( 1, 1 );
+ if( text.length() > 5000 ) m_label.set_markup( text.substr( 0, 5000 ) );
+ else m_label.set_markup( text );
m_counter = 0;
}
@@ -76,7 +98,7 @@ void Tooltip::show_tooltip()
if( m_label.get_text().empty() ) return;
#ifdef _DEBUG
- std::cout << "Tooltip::show_tooltip" << m_label.get_text() << std::endl;
+ std::cout << "Tooltip::show_tooltip " << m_label.get_text() << std::endl;
#endif
int x_mouse, y_mouse;
@@ -117,5 +139,5 @@ void Tooltip::hide_tooltip()
m_counter = 10000;
hide();
- m_label.set_text( std::string() );
+ m_label.set_text( "" );
}
diff --git a/src/skeleton/tooltip.h b/src/skeleton/tooltip.h
index 8a1959ef..b3181a25 100644
--- a/src/skeleton/tooltip.h
+++ b/src/skeleton/tooltip.h
@@ -22,10 +22,13 @@ namespace SKELETON
public:
Tooltip();
+ ~Tooltip() noexcept;
+
void clock_in();
void modify_font_label( const std::string& fontname );
void set_text( const std::string& text );
+ void set_markup( const std::string& text );
void set_min_width( const int min_width ){ m_min_width = min_width; }
void show_tooltip();
diff --git a/src/skeleton/treeviewbase.cpp b/src/skeleton/treeviewbase.cpp
index a0923930..e8ddf13c 100644
--- a/src/skeleton/treeviewbase.cpp
+++ b/src/skeleton/treeviewbase.cpp
@@ -19,8 +19,7 @@ JDTreeViewBase::JDTreeViewBase()
}
-JDTreeViewBase::~JDTreeViewBase() noexcept
-{}
+JDTreeViewBase::~JDTreeViewBase() noexcept = default;
//
@@ -179,19 +178,9 @@ void JDTreeViewBase::goto_bottom()
{
if( ! get_row_size() ) return;
- Gtk::TreePath path = get_model()->get_path( *( std::prev( get_model()->children().end() ) ) );
-
- // ディレクトリを開いている時、一番下の行に移動
- Gtk::TreePath path_prev = path;
- while( ! path.empty() ){
- Gtk::TreePath path_tmp = next_path( path );
- if( path_tmp == path ) break; // 変化が無くなったらbreak
- path_prev = path;
- path = path_tmp;
- }
-
- scroll_to_row( path_prev, 0 );
- set_cursor( path_prev );
+ Gtk::TreePath path = get_model()->get_path( *std::prev( get_model()->children().end() ) );
+ scroll_to_row( path, 0 );
+ set_cursor( path );
}
diff --git a/src/skeleton/undobuffer.h b/src/skeleton/undobuffer.h
index 2d63cbef..9f09cafb 100644
--- a/src/skeleton/undobuffer.h
+++ b/src/skeleton/undobuffer.h
@@ -56,7 +56,7 @@ namespace SKELETON
public:
UNDO_BUFFER();
- virtual ~UNDO_BUFFER() noexcept {}
+ virtual ~UNDO_BUFFER() noexcept = default;
SIG_UNDO sig_undo(){ return m_sig_undo; }
SIG_REDO sig_redo(){ return m_sig_redo; }
diff --git a/src/skeleton/view.cpp b/src/skeleton/view.cpp
index d0b6290d..cb4fea7d 100644
--- a/src/skeleton/view.cpp
+++ b/src/skeleton/view.cpp
@@ -275,7 +275,7 @@ void View::slot_hide_popupmenu()
//
// ラベルやステータスバーの色
//
-std::string View::get_color()
+std::string View::get_color() const
{
if( is_broken() ) return "red";
else if( is_old() ) return "blue";
diff --git a/src/skeleton/view.h b/src/skeleton/view.h
index 7a71ea18..ca0ef5ee 100644
--- a/src/skeleton/view.h
+++ b/src/skeleton/view.h
@@ -44,6 +44,12 @@ namespace SKELETON
// ツールバーに表示する文字列
std::string m_label;
+ // ツールバーのツールチップに表示する文字列
+ std::string m_tooltip_label;
+
+ // ツールバーに表示する文字列にmarkupを使用するか
+ bool m_label_use_markup;
+
// メインウィンドウのタイトルに表示する文字
std::string m_title;
@@ -100,7 +106,10 @@ namespace SKELETON
CONTROL::Control& get_control(){ return m_control; }
// ツールバーに表示するラベル
- void set_label( const std::string& label ){ m_label = label; }
+ void set_label( const std::string& label, const bool use_markup = false ){ m_label = label; m_label_use_markup = use_markup; }
+
+ // ツールバーに表示するラベルのツールチップ
+ void set_tooltip_label( const std::string& label ){ m_tooltip_label = label; }
// メインウィンドウのタイトルに表示する文字列
void set_title( const std::string& title ){ m_title = title; }
@@ -164,11 +173,11 @@ namespace SKELETON
SIG_RESIZE_POPUP sig_resize_popup(){ return m_sig_resize_popup; }
View( const std::string& url, const std::string& arg1 = std::string(), const std::string& arg2 = std::string() );
- ~View() noexcept {}
+ ~View() noexcept = default;
virtual void save_session() = 0;
- virtual const std::string& get_url(){ return m_url; }
+ virtual const std::string& get_url() const { return m_url; }
const std::string& get_url_admin();
virtual void set_parent_win( Gtk::Window* parent_win ){ m_parent_win = parent_win; }
@@ -178,7 +187,7 @@ namespace SKELETON
virtual void update_url( const std::string& url_old, const std::string& url_new );
// 検索文字列
- const std::string& get_search_query(){ return m_search_query; }
+ const std::string& get_search_query() const { return m_search_query; }
// ツールバーのID
// タブの切り替えのときに Admin から参照される
@@ -210,20 +219,26 @@ namespace SKELETON
const std::string& arg2 = {} ) { return true; }
// コピー用のURL
- virtual std::string url_for_copy(){ return m_url; }
+ virtual std::string url_for_copy() const { return m_url; }
// ツールバーのラベルに表示する文字列
- const std::string& get_label(){ return m_label; }
+ const std::string& get_label() const { return m_label; }
+
+ // ツールバーのラベルのツールチップに表示する文字列
+ const std::string& get_tooltip_label() const { return m_tooltip_label; }
+
+ // ツールバーのラベルに表示する文字列にmarkupを使用するか
+ bool get_label_use_markup() const { return m_label_use_markup; }
// メインウィンドウのタイトルバーに表示する文字列
- virtual const std::string& get_title(){ return m_title; }
+ virtual const std::string& get_title() const { return m_title; }
// メインウィンドウのステータスバーに表示する文字列
- virtual const std::string& get_status(){ return m_status; }
+ virtual const std::string& get_status() const { return m_status; }
// クライアント領域の幅、高さ
- virtual int width_client(){ return m_width_client; }
- virtual int height_client(){ return m_height_client; }
+ virtual int width_client() const { return m_width_client; }
+ virtual int height_client() const { return m_height_client; }
void set_width_client( int val ){ m_width_client = val; }
void set_height_client( int val ){ m_height_client = val; }
@@ -241,28 +256,28 @@ namespace SKELETON
void set_reget( const bool reget ){ m_reget = reget; }
// アイコンのID取得
- virtual int get_icon( const std::string& iconname ){ return -1; }
+ virtual int get_icon( const std::string& iconname ) const { return -1; }
// ロード中
virtual bool is_loading() const { return false; }
// 更新した
- virtual bool is_updated(){ return false;}
+ virtual bool is_updated() const { return false; }
// 更新チェックして更新可能か
- virtual bool is_check_update(){ return false;}
+ virtual bool is_check_update() const { return false; }
// 古いデータか
- virtual bool is_old(){ return false;}
+ virtual bool is_old() const { return false; }
// 壊れているか
- virtual bool is_broken(){ return false; }
+ virtual bool is_broken() const { return false; }
// レス数が最大表示可能数以上か
virtual bool is_overflow() const noexcept { return false; }
// ラベルやステータスバーの色
- std::string get_color();
+ std::string get_color() const;
// キーを押した
virtual bool slot_key_press( GdkEventKey* event ){ return false; }
@@ -279,7 +294,7 @@ namespace SKELETON
virtual void show_view(){}
virtual void redraw_view(){}
virtual void redraw_scrollbar(){}
- virtual void relayout(){}
+ virtual void relayout( const bool completely = false ){}
virtual void update_view(){}
virtual void update_finish(){}
virtual void focus_view(){}
diff --git a/src/skeleton/viewnote.cpp b/src/skeleton/viewnote.cpp
index e9f793cb..42b97abf 100644
--- a/src/skeleton/viewnote.cpp
+++ b/src/skeleton/viewnote.cpp
@@ -33,6 +33,9 @@ ViewNotebook::ViewNotebook( DragableNoteBook* parent )
}
+ViewNotebook::~ViewNotebook() noexcept = default;
+
+
//
// 描画イベント
//
diff --git a/src/skeleton/viewnote.h b/src/skeleton/viewnote.h
index 8ff4f6d2..1e19cf1b 100644
--- a/src/skeleton/viewnote.h
+++ b/src/skeleton/viewnote.h
@@ -21,6 +21,7 @@ namespace SKELETON
public:
ViewNotebook( DragableNoteBook* parent );
+ ~ViewNotebook() noexcept;
void redraw_scrollbar();
diff --git a/src/skeleton/vpaned.cpp b/src/skeleton/vpaned.cpp
index c795efde..32831a8e 100644
--- a/src/skeleton/vpaned.cpp
+++ b/src/skeleton/vpaned.cpp
@@ -14,6 +14,9 @@ JDVPaned::JDVPaned( const int fixmode )
{}
+JDVPaned::~JDVPaned() noexcept = default;
+
+
void JDVPaned::on_realize()
{
Gtk::VPaned::on_realize();
diff --git a/src/skeleton/vpaned.h b/src/skeleton/vpaned.h
index 0cc5200c..d30b4f9a 100644
--- a/src/skeleton/vpaned.h
+++ b/src/skeleton/vpaned.h
@@ -19,7 +19,7 @@ namespace SKELETON
public:
JDVPaned( const int fixmode );
- ~JDVPaned() noexcept {}
+ ~JDVPaned() noexcept;
VPaneControl& get_ctrl(){ return m_pctrl; }
diff --git a/src/type.h b/src/type.h
index 3bb570b3..3b24a58c 100644
--- a/src/type.h
+++ b/src/type.h
@@ -29,6 +29,7 @@ enum
TYPE_HISTITEM,
TYPE_USRCMD,
TYPE_LINKFILTER,
+ TYPE_REPLACESTR,
TYPE_SEPARATOR,
TYPE_FILE,
diff --git a/src/updatemanager.cpp b/src/updatemanager.cpp
index 7fd496db..542cf408 100644
--- a/src/updatemanager.cpp
+++ b/src/updatemanager.cpp
@@ -110,7 +110,7 @@ void CheckUpdate_Manager::push_back( const std::string& url, const bool open )
int num_from, num_to;
std::string num_str;
const std::string url_dat = DBTREE::url_dat( url, num_from, num_to, num_str );
- const std::string url_subject = DBTREE::url_subject( url );
+ const std::string boardbase = DBTREE::url_boardbase( url );
// スレ
if( ! url_dat.empty() ){
@@ -122,10 +122,10 @@ void CheckUpdate_Manager::push_back( const std::string& url, const bool open )
}
// 板
- else if( ! url_subject.empty() ){
+ else if( ! boardbase.empty() ){
#ifdef _DEBUG
std::cout << "type = board\n"
- << url_subject << std::endl;
+ << boardbase << std::endl;
#endif
urllist = DBTREE::board_get_check_update_articles( url );
}
@@ -179,7 +179,7 @@ void CheckUpdate_Manager::pop_front()
int num_from, num_to;
std::string num_str;
const std::string url_dat = DBTREE::url_dat( url, num_from, num_to, num_str );
- const std::string url_subject = DBTREE::url_subject( url );
+ const std::string boardbase = DBTREE::url_boardbase( url );
// スレ
if( ! url_dat.empty() ){
@@ -188,7 +188,7 @@ void CheckUpdate_Manager::pop_front()
}
// 板
- else if( ! url_subject.empty() ){
+ else if( ! boardbase.empty() ){
if( DBTREE::board_status( url ) & STATUS_UPDATE ) urls_board += url + " ";
}
diff --git a/src/urlreplacemanager.cpp b/src/urlreplacemanager.cpp
index fa9928a9..839c2d66 100644
--- a/src/urlreplacemanager.cpp
+++ b/src/urlreplacemanager.cpp
@@ -44,9 +44,11 @@ using namespace CORE;
"# 詳細な書式はマニュアルを参照してください。\n" \
"# この機能を無効にする場合は、このファイルの内容を空にして保存してください。\n" \
"#\n" \
- "http://www\\.youtube\\.com/watch\\?(|[^#]+&)v=([^&#/]+) http://img.youtube.com/vi/$2/0.jpg\n" \
- "http://youtu\\.be/([^#&=/]+) http://img.youtube.com/vi/$1/0.jpg\n" \
- "http://img\\.youtube\\.com/vi/[^/]+/0.jpg $0 $THUMBNAIL\n" \
+ "(http://[^.]+\\.2ch\\.net/test/read\\.cgi)\\?bbs=([^&]+)&[amp]*key=([0-9]+)(&[amp]*st=([0-9]+))?(&[amp]*to=([0-9]+))? $1/$2/$3/$5-$7 $BREAK\n" \
+ "http://jbbs\\.(shitaraba\\.(net|com)|livedoor\\.jp)/(bbs/read(_archive)?\\.cgi/)?([^/]+/[0-9]+/)(storage/)?([0-9]+/?[-0-9ln]*)(\\.html)?$ http://jbbs.shitaraba.net/bbs/read.cgi/$5$7 $BREAK\n" \
+ "https?://www\\.youtube\\.com/watch\\?(|[^#]+&)v=([^&#/]+) http://img.youtube.com/vi/$2/0.jpg\n" \
+ "https?://youtu\\.be/([^#&=/]+) http://img.youtube.com/vi/$1/0.jpg\n" \
+ "https?://img\\.youtube\\.com/vi/[^/]+/0.jpg $0 $THUMBNAIL\n" \
"\n"
@@ -68,15 +70,37 @@ Urlreplace_Manager::Urlreplace_Manager()
}
}
+Urlreplace_Manager::~Urlreplace_Manager()
+{
+ if( ! m_list_cmd.empty() ){
+ std::list< UrlreplaceItem* >::const_iterator it = m_list_cmd.begin();
+ for( ; it != m_list_cmd.end(); ++it ){
+ delete (*it);
+ }
+ m_list_cmd.clear();
+ }
+}
+
//
// conf -> リスト
//
void Urlreplace_Manager::conf2list( const std::string& conf )
{
- m_list_cmd.clear();
+ if( ! m_list_cmd.empty() ){
+ std::list< UrlreplaceItem* >::const_iterator it = m_list_cmd.begin();
+ for( ; it != m_list_cmd.end(); ++it ){
+ delete (*it);
+ }
+ m_list_cmd.clear();
+ }
if( conf.empty() ) return;
+ const bool icase = false;
+ const bool newline = true;
+ const bool migemo = false;
+ const bool wchar = false;
+
std::list< std::string > lines = MISC::get_lines( conf );
if( lines.size() == 0 ) return;
@@ -88,19 +112,32 @@ void Urlreplace_Manager::conf2list( const std::string& conf )
std::list< std::string > line = MISC::StringTokenizer( *it, '\t' );
if( line.size() < 2 ) continue;
- UrlreplaceItem item;
+ UrlreplaceItem *item = new UrlreplaceItem();
std::string ctrl;
std::list < std::string >::iterator str = line.begin();
// 1: 検索URL
- item.match = *str;
+ if( (*str).empty() || ! item->creg.set( *str, icase, newline, migemo, wchar ) ){
+ delete item;
+ continue;
+ }
// 2: 置換URL
- item.replace = *(++str);
+ if( (*++str).empty() ){
+ delete item;
+ continue;
+ }
+ item->replace = *str;
+ char tgt_text[] = "$0";
+ char rep_text[] = "\\0";
+ for( int i = 0; i <= 9; i++ ){
+ tgt_text[ 1 ] = rep_text[ 1 ] = '0' + i;
+ item->replace = MISC::replace_str( item->replace, tgt_text, rep_text );
+ }
// 3: リファラURL
- item.referer.clear();
- if( (++str) != line.end() ) item.referer = *str;
+ if( (++str) != line.end() ) item->referer = *str;
+ else item->referer.clear();
// 4: コントロール
- item.imgctrl = IMGCTRL_NONE;
- item.match_break = false;
+ item->imgctrl = IMGCTRL_NONE;
+ item->match_break = false;
if( (++str) != line.end() ){
ctrl = *str;
int imgctrl = IMGCTRL_INIT;
@@ -122,13 +159,13 @@ void Urlreplace_Manager::conf2list( const std::string& conf )
imgctrl += IMGCTRL_THUMBNAIL;
}
- if( imgctrl != IMGCTRL_INIT ) item.imgctrl = imgctrl;
+ if( imgctrl != IMGCTRL_INIT ) item->imgctrl = imgctrl;
// 正規表現に一致したら以降の判定を行わない
- item.match_break = ( ctrl.find( "$BREAK" ) != std::string::npos );
+ item->match_break = ( ctrl.find( "$BREAK" ) != std::string::npos );
}
- if( ! item.match.empty() && ! item.replace.empty() ) m_list_cmd.push_back( item );
+ m_list_cmd.push_back( item );
}
}
@@ -143,25 +180,19 @@ bool Urlreplace_Manager::exec( std::string &url )
JDLIB::Regex regex;
const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
// いずれかの正規表現に一致するか
bool matched = false;
- std::list< UrlreplaceItem >::iterator it = m_list_cmd.begin();
+ std::list< UrlreplaceItem* >::const_iterator it = m_list_cmd.begin();
for( ; it != m_list_cmd.end(); ++it ){
- if( regex.exec( (*it).match, url,
- offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.match( (*it)->creg, url, offset ) ){
matched = true;
// 置換URLの変換
- url = (*it).replace;
- replace( regex, url );
+ url = regex.replace( (*it)->replace );
// URLが空になったか、以降の判定を行わない
- if( url.empty() || (*it).match_break ) break;
+ if( url.empty() || (*it)->match_break ) break;
}
}
return matched;
@@ -171,33 +202,27 @@ bool Urlreplace_Manager::exec( std::string &url )
//
// URLからリファラを求める
//
-bool Urlreplace_Manager::referer( const std::string &url, std::string &referer )
+bool Urlreplace_Manager::referer( const std::string &url, std::string &refstr )
{
if( m_list_cmd.empty() ) return false;
- referer = url;
+ refstr = url;
JDLIB::Regex regex;
const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
// いずれかの正規表現に一致するか
bool matched = false;
- std::list< UrlreplaceItem >::iterator it = m_list_cmd.begin();
+ std::list< UrlreplaceItem* >::const_iterator it = m_list_cmd.begin();
for( ; it != m_list_cmd.end(); ++it ){
- if( regex.exec( (*it).match, referer,
- offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.match( (*it)->creg, refstr, offset ) ){
matched = true;
// リファラURLの変換
- referer = (*it).referer;
- replace( regex, referer );
+ refstr = regex.replace( (*it)->referer );
// URLが空になったか、以降の判定を行わない
- if( referer.empty() || (*it).match_break ) break;
+ if( refstr.empty() || (*it)->match_break ) break;
}
}
return matched;
@@ -205,76 +230,28 @@ bool Urlreplace_Manager::referer( const std::string &url, std::string &referer )
//
-// URLの画像コントロールを取得する (URLキャッシュ)
+// URLの画像コントロールを取得する
//
int Urlreplace_Manager::get_imgctrl( const std::string &url )
{
if( m_list_cmd.empty() ) return IMGCTRL_NONE;
- // 取得済みのURLか
- std::map< std::string, int >::iterator it = m_map_imgctrl.find( url );
- if( it != m_map_imgctrl.end() ) return ( *it ).second;
-
- // 新たに取得してキャッシュする
- int imgctrl = get_imgctrl_impl( url );
- m_map_imgctrl.insert( make_pair( url, imgctrl ) );
-
- return imgctrl;
-}
-
-//
-// URLの画像コントロールを取得する
-//
-int Urlreplace_Manager::get_imgctrl_impl( const std::string &url )
-{
int imgctrl = IMGCTRL_NONE;
JDLIB::Regex regex;
const size_t offset = 0;
- const bool icase = false;
- const bool newline = true;
- const bool usemigemo = false;
- const bool wchar = false;
// いずれかの正規表現に一致するか
- std::list< UrlreplaceItem >::iterator it = m_list_cmd.begin();
+ std::list< UrlreplaceItem* >::const_iterator it = m_list_cmd.begin();
for( ; it != m_list_cmd.end(); ++it ){
- if( regex.exec( (*it).match, url,
- offset, icase, newline, usemigemo, wchar ) ){
+ if( regex.match( (*it)->creg, url, offset ) ){
// 画像コントロールを取得
- imgctrl = (*it).imgctrl;
+ imgctrl = (*it)->imgctrl;
// 以降の判定を行わない
- if( (*it).match_break ) break;
+ if( (*it)->match_break ) break;
}
}
return imgctrl;
}
-
-
-//
-// 置換文字列を変換
-// \0 ... \9 ( $0 ... $9 ) : 正規表現の部分一致
-//
-void Urlreplace_Manager::replace( JDLIB::Regex &regex, std::string &str )
-{
- if( str.empty() ) return;
-
- char rep1[] = "\\0";
- char rep2[] = "$0";
- for( int i = 0; i < 9; i++ ){
- if( regex.pos( i ) == -1 ){
- break;
- }
- rep1[ 1 ] = '0' + i;
- if( str.find( rep1 ) != std::string::npos ){
- str = MISC::replace_str( str, rep1, regex.str( i ) );
- }
- rep2[ 1 ] = '0' + i;
- if( str.find( rep2 ) != std::string::npos ){
- str = MISC::replace_str( str, rep2, regex.str( i ) );
- }
- }
-}
-
diff --git a/src/urlreplacemanager.h b/src/urlreplacemanager.h
index 14c51eb1..95dcb003 100644
--- a/src/urlreplacemanager.h
+++ b/src/urlreplacemanager.h
@@ -24,7 +24,7 @@ namespace CORE
struct UrlreplaceItem
{
- std::string match;
+ JDLIB::RegexPattern creg;
std::string replace;
std::string referer;
int imgctrl;
@@ -33,19 +33,18 @@ namespace CORE
class Urlreplace_Manager
{
- std::list< UrlreplaceItem > m_list_cmd;
- std::map< std::string, int > m_map_imgctrl; // 画像コントロールのキャッシュ
+ std::list< UrlreplaceItem* > m_list_cmd;
public:
Urlreplace_Manager();
- virtual ~Urlreplace_Manager() noexcept {}
+ virtual ~Urlreplace_Manager();
// URLを任意の正規表現で変換する
bool exec( std::string& url );
// URLからリファラを求める
- bool referer( const std::string& url, std::string& referer );
+ bool referer( const std::string& url, std::string& refstr );
// URLの画像コントロールを取得する
int get_imgctrl( const std::string& url );
@@ -53,10 +52,6 @@ namespace CORE
private:
void conf2list( const std::string& conf );
- int get_imgctrl_impl( const std::string& url );
-
- // 置換文字列を変換
- void replace( JDLIB::Regex& regex, std::string& str );
};
///////////////////////////////////////
diff --git a/src/usrcmdmanager.cpp b/src/usrcmdmanager.cpp
index ef680f65..2a3ba677 100644
--- a/src/usrcmdmanager.cpp
+++ b/src/usrcmdmanager.cpp
@@ -76,63 +76,11 @@ Usrcmd_Manager::Usrcmd_Manager()
{
std::string xml;
if( CACHE::load_rawdata( CACHE::path_usrcmd(), xml ) ) m_document.init( xml );
- else txt2xml();
analyze_xml();
}
-//
-// 旧式の設定ファイル(テキスト形式)をxmlに変換する
-//
-void Usrcmd_Manager::txt2xml()
-{
- m_document.clear();
-
- // 旧設定ファイルからユーザーコマンドを読み込み
- const std::string file_usrcmd = CACHE::path_usrcmd_old();
- std::string usrcmd;
-
- if( CACHE::load_rawdata( file_usrcmd, usrcmd ) ){
-
- XML::Dom* root = m_document.appendChild( XML::NODE_TYPE_ELEMENT, std::string( ROOT_NODE_NAME_USRCMD ) );
- XML::Dom* subdir = root;
-
- std::list< std::string > list_usrcmd = MISC::get_lines( usrcmd );
- list_usrcmd = MISC::remove_commentline_from_list( list_usrcmd );
- list_usrcmd = MISC::remove_space_from_list( list_usrcmd );
- list_usrcmd = MISC::remove_nullline_from_list( list_usrcmd );
-
- // ユーザコマンドが 3つ以上 (廃止した max_show_usrcmd 設定の初期値 )より
- // 大きい場合はサブディレクトリ化する
- if( list_usrcmd.size() >= 3 * 2 ){
- subdir = root->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_DIR ) );
- subdir->setAttribute( "name", "ユーザコマンド" );
- subdir->setAttribute( "open", "y" );
- }
-
- std::list< std::string >::iterator it;
- for( it = list_usrcmd.begin(); it != list_usrcmd.end(); ++it ){
-
- const std::string name = *( it++ );
- if( it == list_usrcmd.end() ) break;
- const std::string cmd = *it;
-
- XML::Dom* usrcmd = subdir->appendChild( XML::NODE_TYPE_ELEMENT, XML::get_name( TYPE_USRCMD ) );
- usrcmd->setAttribute( "name", name );
- usrcmd->setAttribute( "data", cmd );
- }
-
-#ifdef _DEBUG
- std::cout << "Usrcmd_Manager::txt2xml\n";
- std::cout << "nodes = " << m_document.childNodes().size() << std::endl;
- std::cout << m_document.get_xml() << std::endl;
-#endif
- save_xml();
- }
-}
-
-
//
// XML に含まれるコマンド情報を取り出してデータベースを更新
//
@@ -335,7 +283,7 @@ std::string Usrcmd_Manager::replace_cmd( const std::string& cmd,
cmd_out = MISC::replace_str( cmd_out, "$DATNAMEL", DBTREE::article_key( link ) );
cmd_out = MISC::replace_str( cmd_out, "$DATNAME", DBTREE::article_key( url ) );
- cmd_out = MISC::replace_str( cmd_out, "$TITLE", DBTREE::article_subject( url ) );
+ cmd_out = MISC::replace_str( cmd_out, "$TITLE", MISC::to_plain( DBTREE::article_subject( url ) ) );
cmd_out = MISC::replace_str( cmd_out, "$BOARDNAME", DBTREE::board_name( url ) );
// 範囲選択した文字列
@@ -343,15 +291,15 @@ std::string Usrcmd_Manager::replace_cmd( const std::string& cmd,
if( cmd_out.find( "$TEXTIU" ) != std::string::npos ){
if( ! show_replacetextdiag( texti, "$TEXTIU" ) ) return std::string();
- cmd_out = MISC::replace_str( cmd_out, "$TEXTIU", MISC::charset_url_encode_split( texti, "UTF-8" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$TEXTIU", MISC::url_encode_split( texti, CHARCODE_UTF8 ) );
}
if( cmd_out.find( "$TEXTIX" ) != std::string::npos ){
if( ! show_replacetextdiag( texti, "$TEXTIX" ) ) return std::string();
- cmd_out = MISC::replace_str( cmd_out, "$TEXTIX", MISC::charset_url_encode_split( texti, "EUC-JP" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$TEXTIX", MISC::url_encode_split( texti, CHARCODE_EUCJP ) );
}
if( cmd_out.find( "$TEXTIE" ) != std::string::npos ){
if( ! show_replacetextdiag( texti, "$TEXTIE" ) ) return std::string();
- cmd_out = MISC::replace_str( cmd_out, "$TEXTIE", MISC::charset_url_encode_split( texti, "MS932" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$TEXTIE", MISC::url_encode_split( texti, CHARCODE_SJIS ) );
}
if( cmd_out.find( "$TEXTI" ) != std::string::npos ){
if( ! show_replacetextdiag( texti, "$TEXTI" ) ) return std::string();
@@ -359,13 +307,13 @@ std::string Usrcmd_Manager::replace_cmd( const std::string& cmd,
}
if( cmd_out.find( "$TEXTU" ) != std::string::npos ){
- cmd_out = MISC::replace_str( cmd_out, "$TEXTU", MISC::charset_url_encode_split( texti, "UTF-8" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$TEXTU", MISC::url_encode_split( texti, CHARCODE_UTF8 ) );
}
if( cmd_out.find( "$TEXTX" ) != std::string::npos ){
- cmd_out = MISC::replace_str( cmd_out, "$TEXTX", MISC::charset_url_encode_split( texti, "EUC-JP" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$TEXTX", MISC::url_encode_split( texti, CHARCODE_EUCJP ) );
}
if( cmd_out.find( "$TEXTE" ) != std::string::npos ){
- cmd_out = MISC::replace_str( cmd_out, "$TEXTE", MISC::charset_url_encode_split( texti, "MS932" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$TEXTE", MISC::url_encode_split( texti, CHARCODE_SJIS ) );
}
if( cmd_out.find( "$TEXT" ) != std::string::npos ){
cmd_out = MISC::replace_str( cmd_out, "$TEXT", texti );
@@ -376,15 +324,15 @@ std::string Usrcmd_Manager::replace_cmd( const std::string& cmd,
if( cmd_out.find( "$INPUTU" ) != std::string::npos ){
if( ! show_replacetextdiag( input, "$INPUTU" ) ) return std::string();
- cmd_out = MISC::replace_str( cmd_out, "$INPUTU", MISC::charset_url_encode_split( input, "UTF-8" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$INPUTU", MISC::url_encode_split( input, CHARCODE_UTF8 ) );
}
if( cmd_out.find( "$INPUTX" ) != std::string::npos ){
if( ! show_replacetextdiag( input, "$INPUTX" ) ) return std::string();
- cmd_out = MISC::replace_str( cmd_out, "$INPUTX", MISC::charset_url_encode_split( input, "EUC-JP" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$INPUTX", MISC::url_encode_split( input, CHARCODE_EUCJP ) );
}
if( cmd_out.find( "$INPUTE" ) != std::string::npos ){
if( ! show_replacetextdiag( input, "$INPUTE" ) ) return std::string();
- cmd_out = MISC::replace_str( cmd_out, "$INPUTE", MISC::charset_url_encode_split( input, "MS932" ) );
+ cmd_out = MISC::replace_str( cmd_out, "$INPUTE", MISC::url_encode_split( input, CHARCODE_SJIS ) );
}
if( cmd_out.find( "$INPUT" ) != std::string::npos ){
if( ! show_replacetextdiag( input, "$INPUT" ) ) return std::string();
@@ -411,7 +359,9 @@ std::string Usrcmd_Manager::replace_cmd( const std::string& cmd,
//
bool Usrcmd_Manager::is_sensitive( int num, const std::string& link, const std::string& selection )
{
+#ifdef _WIN32
const unsigned int max_selection_str = 1024;
+#endif
if( num >= m_size ) return false;
@@ -432,7 +382,11 @@ bool Usrcmd_Manager::is_sensitive( int num, const std::string& link, const std::
if( cmd.find( "$TEXT" ) != std::string::npos && cmd.find( "$TEXTI" ) == std::string::npos ){
- if( selection.empty() || selection.length() > max_selection_str ) return false;
+ if( selection.empty()
+#ifdef _WIN32
+ || selection.length() > max_selection_str
+#endif
+ ) return false;
}
if( cmd.find( "$CACHEDIMG" ) != std::string::npos ){
diff --git a/src/usrcmdmanager.h b/src/usrcmdmanager.h
index 2202ebdf..8c185916 100644
--- a/src/usrcmdmanager.h
+++ b/src/usrcmdmanager.h
@@ -27,7 +27,7 @@ namespace CORE
public:
Usrcmd_Manager();
- virtual ~Usrcmd_Manager() noexcept {}
+ virtual ~Usrcmd_Manager() noexcept = default;
XML::Document& xml_document() { return m_document; }
void analyze_xml();
@@ -74,8 +74,6 @@ namespace CORE
const std::string& str_select );
private:
- void txt2xml();
-
bool show_replacetextdiag( std::string& texti, const std::string& title );
void set_cmd( const std::string& cmd );
diff --git a/src/xml/document.h b/src/xml/document.h
index c113155a..14983ede 100644
--- a/src/xml/document.h
+++ b/src/xml/document.h
@@ -30,7 +30,7 @@ namespace XML
// 何も無い状態からノードツリーを作る場合
Document();
- ~Document() noexcept {}
+ ~Document() noexcept = default;
// このクラスは代入可能
Document& operator=( const Document& document );
diff --git a/src/xml/dom.cpp b/src/xml/dom.cpp
index e0747b47..991eb28c 100644
--- a/src/xml/dom.cpp
+++ b/src/xml/dom.cpp
@@ -104,7 +104,7 @@ void Dom::parse( const std::string& str )
std::string next_source;
// "<"を探す
- tag_lt_pos = str.find( "<", current_pos );
+ tag_lt_pos = str.find_first_of( '<', current_pos );
// タグの前のテキストノード
if( current_pos < tag_lt_pos )
@@ -125,7 +125,7 @@ void Dom::parse( const std::string& str )
// 要素ノード
else if( current_pos == tag_lt_pos )
{
- tag_gt_pos = str.find( ">", tag_lt_pos + 1 );
+ tag_gt_pos = str.find_first_of( '>', tag_lt_pos + 1 );
current_pos = tag_gt_pos + 1;
@@ -138,7 +138,7 @@ void Dom::parse( const std::string& str )
// タグ構造が壊れてる場合
size_t broken_pos = 0;
if( open_tag.empty() || ! is_alpha ) continue;
- else if( ( broken_pos = open_tag.find( "<" ) ) != std::string::npos )
+ else if( ( broken_pos = open_tag.find_first_of( '<' ) ) != std::string::npos )
{
current_pos += broken_pos;
continue;
@@ -183,27 +183,30 @@ void Dom::parse( const std::string& str )
{
// count は見つける必要がある終了タグの数
size_t close_tag_lt_pos = 0, close_tag_gt_pos = 0, count = 1;
- while( ( close_tag_lt_pos = str.find( "<", current_pos ) ) != std::string::npos
- && ( close_tag_gt_pos = str.find( ">", close_tag_lt_pos + 1 ) ) != std::string::npos )
+ while( ( close_tag_lt_pos = str.find_first_of( '<', current_pos ) ) != std::string::npos
+ && ( close_tag_gt_pos = str.find_first_of( '>', close_tag_lt_pos + 1 ) ) != std::string::npos )
{
current_pos = close_tag_gt_pos + 1;
// タグの中身を取り出す
- const std::string close_tag = MISC::tolower_str( str.substr( close_tag_lt_pos + 1, close_tag_gt_pos - close_tag_lt_pos - 1 ) );
+ std::string close_tag = str.substr( close_tag_lt_pos + 1, close_tag_gt_pos - close_tag_lt_pos - 1 );
+ if( m_html ) close_tag = MISC::tolower_str( close_tag );
// タグ構造が壊れてる場合
if( close_tag.empty() ) continue;
- else if( ( broken_pos = close_tag.find( "<" ) ) != std::string::npos )
+ else if( ( broken_pos = close_tag.find_first_of( '<' ) ) != std::string::npos )
{
current_pos += broken_pos;
continue;
}
// 空要素でない同名の開始タグを見つけたらカウントを増やす
- if( close_tag.compare( 0, name.length(), name ) == 0
- && close_tag.compare( close_tag.length() - 1, 1, "/" ) != 0 ) ++count;
+ if( ( close_tag.compare( 0, element_name.length(), element_name ) == 0
+ || ( m_html && close_tag.compare( 0, name.length(), name ) == 0 ) )
+ && close_tag.compare( close_tag.length() - 1, 1, "/" ) != 0 ) ++count;
// 終了タグを見つけたらカウントを減らす
- else if( close_tag.compare( 0, name.length() + 1, "/" + name ) == 0 ) --count;
+ else if( close_tag.compare( 0, element_name.length() + 1, "/" + element_name ) == 0
+ || ( m_html && close_tag.compare( 0, name.length() + 1, "/" + name ) == 0 ) ) --count;
// 終了タグを見つける必要数が 0 になったらループを抜ける
if( count <= 0 ) break;
@@ -527,30 +530,6 @@ void Dom::append_treestore( Glib::RefPtr< Gtk::TreeStore >& treestore,
-//
-// プロパティを扱うアクセッサ
-//
-int Dom::nodeType()
-{
- return m_nodeType;
-}
-
-std::string Dom::nodeName()
-{
- return m_nodeName;
-}
-
-std::string Dom::nodeValue()
-{
- return m_nodeValue;
-}
-
-void Dom::nodeValue( const std::string& value )
-{
- m_nodeValue = value;
-}
-
-
//
// getElementById()
//
@@ -618,33 +597,10 @@ Dom* Dom::ownerDocument()
}
-//
-// ノード:parentNode
-//
-Dom* Dom::parentNode()
-{
- return m_parentNode;
-}
-
-void Dom::parentNode( Dom* parent )
-{
- m_parentNode = parent;
-}
-
-
-//
-// ノード:hasChildNodes
-//
-bool Dom::hasChildNodes()
-{
- return ! m_childNodes.empty();
-}
-
-
//
// ノード:childNodes
//
-DomList Dom::childNodes()
+DomList Dom::childNodes() const
{
DomList result;
@@ -711,15 +667,11 @@ Dom* Dom::lastChild()
//
Dom* Dom::appendChild( const int node_type, const std::string& node_name )
{
- Dom* node = 0;
-
- {
- node = new Dom( node_type, node_name, m_html );
+ Dom* node = new Dom( node_type, node_name, m_html );
- node->parentNode( this );
+ node->parentNode( this );
- m_childNodes.push_back( node );
- }
+ m_childNodes.push_back( node );
return node;
}
@@ -745,7 +697,9 @@ bool Dom::removeChild( Dom* node )
//
Dom* Dom::replaceChild( const int node_type, const std::string& node_name, Dom* oldNode )
{
- Dom* newNode = 0;
+ Dom* newNode = nullptr;
+
+ if( ! oldNode ) return newNode;
newNode = new Dom( node_type, node_name );
@@ -773,7 +727,9 @@ Dom* Dom::replaceChild( const int node_type, const std::string& node_name, Dom*
//
Dom* Dom::insertBefore( const int node_type, const std::string& node_name, Dom* insNode )
{
- Dom* newNode = 0;
+ Dom* newNode = nullptr;
+
+ if( ! insNode ) return newNode;
newNode = new Dom( node_type, node_name );
@@ -842,33 +798,10 @@ Dom* Dom::nextSibling()
}
-//
-// 属性:attributes
-//
-std::map< std::string, std::string > Dom::attributes()
-{
- return m_attributes;
-}
-
-void Dom::attributes( const std::map< std::string, std::string > attributes )
-{
- if( ! attributes.empty() ) m_attributes = attributes;
-}
-
-
-//
-// 属性:hasAttributes()
-//
-bool Dom::hasAttributes()
-{
- return ! m_attributes.empty();
-}
-
-
//
// 属性:hasAttribute()
//
-bool Dom::hasAttribute( const std::string& name )
+bool Dom::hasAttribute( const std::string& name ) const
{
if( name.empty() ) return false;
diff --git a/src/xml/dom.h b/src/xml/dom.h
index 98c403ad..7069c56b 100644
--- a/src/xml/dom.h
+++ b/src/xml/dom.h
@@ -73,7 +73,7 @@ namespace XML
void parse( const Gtk::TreeModel::Children& children, SKELETON::EditColumns& columns );
// プロパティをセットするアクセッサ
- void parentNode( Dom* parent );
+ void parentNode( Dom* parent ){ m_parentNode = parent; }
void copy_childNodes( const Dom& dom ); // dom の子ノードをコピーする
// ノードを分解して Gtk::TreeStore へ Gtk::TreeModel::Row を追加
@@ -100,10 +100,10 @@ namespace XML
DomList getElementsByTagName( const std::string& name );
// プロパティを扱うアクセッサ
- int nodeType();
- std::string nodeName();
- std::string nodeValue();
- void nodeValue( const std::string& value );
+ int nodeType() const { return m_nodeType; }
+ const std::string& nodeName() const { return m_nodeName; }
+ const std::string& nodeValue() const { return m_nodeValue; }
+ void nodeValue( const std::string& value ) { m_nodeValue = value; }
// ノード
// 注意:appendChild(), replaceChild(), insertBefore() は
@@ -114,9 +114,9 @@ namespace XML
// を返すようにしてあります。
Dom* ownerDocument();
- Dom* parentNode();
- bool hasChildNodes();
- DomList childNodes();
+ Dom* parentNode() const { return m_parentNode; }
+ bool hasChildNodes() const { return ! m_childNodes.empty(); }
+ DomList childNodes() const;
Dom* firstChild();
Dom* lastChild();
Dom* appendChild( const int node_type, const std::string& node_name );
@@ -127,10 +127,13 @@ namespace XML
Dom* nextSibling();
// 属性
- bool hasAttributes();
- std::map< std::string, std::string > attributes();
- void attributes( const std::map< std::string, std::string > attributes );
- bool hasAttribute( const std::string& name );
+ bool hasAttributes() const { return ! m_attributes.empty(); }
+ std::map< std::string, std::string >& attributes(){ return m_attributes; }
+ void attributes( std::map< std::string, std::string > attributes )
+ {
+ if( ! attributes.empty() ){ m_attributes = std::move( attributes ); }
+ }
+ bool hasAttribute( const std::string& name ) const;
std::string getAttribute( const std::string& name );
bool setAttribute( const std::string& name, const std::string& value );
bool setAttribute( const std::string& name, const int value );
diff --git a/src/xml/domlist.cpp b/src/xml/domlist.cpp
index 4e2fa9a8..509e1c90 100644
--- a/src/xml/domlist.cpp
+++ b/src/xml/domlist.cpp
@@ -9,28 +9,10 @@
using namespace XML;
-DomList::DomList()
-{
-
-}
-
-DomList::~DomList()
-{
-
-}
-
-// std::list< Dom* > が代入された場合
-DomList& DomList::operator =( const std::list< Dom* >& list )
-{
- m_list = list;
-
- return *this;
-}
-
// 添字によるアクセス
Dom* DomList::operator []( const unsigned int n )
{
- if( m_list.empty() || n > m_list.size() ) return 0;
+ if( m_list.empty() || n > m_list.size() ) return nullptr;
size_t count = 0;
std::list< Dom* >::iterator it = m_list.begin();
@@ -41,51 +23,14 @@ Dom* DomList::operator []( const unsigned int n )
++it;
}
- return 0;
+ return nullptr;
}
-// 以下 std::list の主なメンバ関数
-
-std::list< Dom* >::iterator DomList::begin()
-{
- return m_list.begin();
-}
-
-std::list< Dom* >::reverse_iterator DomList::rbegin()
-{
- return m_list.rbegin();
-}
-
-std::list< Dom* >::iterator DomList::end()
-{
- return m_list.end();
-}
-
-std::list< Dom* >::reverse_iterator DomList::rend()
-{
- return m_list.rend();
-}
-
-size_t DomList::size() const
-{
- return m_list.size();
-}
-
-size_t DomList::max_size() const
-{
- return m_list.max_size();
-}
-
-bool DomList::empty() const
-{
- return m_list.empty();
-}
-
// 参照ではなくポインタを返す
Dom* DomList::front()
{
- if( m_list.empty() ) return 0;
+ if( m_list.empty() ) return nullptr;
return *m_list.begin();
}
@@ -93,79 +38,7 @@ Dom* DomList::front()
// 参照ではなくポインタを返す
Dom* DomList::back()
{
- if( m_list.empty() ) return 0;
+ if( m_list.empty() ) return nullptr;
return *m_list.end();
}
-
-void DomList::push_front( Dom* dom )
-{
- m_list.push_front( dom );
-}
-
-void DomList::push_back( Dom* dom )
-{
- m_list.push_back( dom );
-}
-
-void DomList::pop_front()
-{
- m_list.pop_front();
-}
-
-void DomList::pop_back()
-{
- m_list.pop_back();
-}
-
-std::list< Dom* >::iterator DomList::insert( std::list< Dom* >::iterator it, Dom* dom )
-{
- return m_list.insert( it, dom );
-}
-
-std::list< Dom* >::iterator DomList::erase( std::list< Dom* >::iterator it )
-{
- return m_list.erase( it );
-}
-
-void DomList::clear()
-{
- m_list.clear();
-}
-
-void DomList::splice( std::list< Dom* >::iterator it, DomList& domlist )
-{
- m_list.splice( it, domlist.m_list );
-}
-
-void DomList::remove( Dom* dom )
-{
- m_list.remove( dom );
-}
-
-void DomList::unique()
-{
- m_list.unique();
-}
-
-void DomList::merge( DomList& domlist )
-{
- m_list.merge( domlist.m_list );
-
-}
-
-void DomList::sort()
-{
- m_list.sort();
-}
-
-void DomList::reverce()
-{
- m_list.reverse();
-}
-
-void DomList::swap( DomList& domlist )
-{
- m_list.swap( domlist.m_list );
-}
-
diff --git a/src/xml/domlist.h b/src/xml/domlist.h
index b9bed8ee..3a38ceaf 100644
--- a/src/xml/domlist.h
+++ b/src/xml/domlist.h
@@ -19,46 +19,46 @@ namespace XML
class DomList
{
- std::list< Dom* > m_list;
+ std::list< Dom* > m_list;
//DomList( const DomList& );
public:
- DomList();
- ~DomList();
+ DomList() = default;
+ ~DomList() noexcept = default;
// std::list< Dom* > が代入された場合
- DomList& operator =( const std::list< Dom* >& list );
+ DomList& operator =( const std::list< Dom* >& list ){ m_list = list; return *this; }
// 添字によるアクセス
Dom* operator []( const unsigned int n );
- std::list< Dom* > get_list() { return m_list; }
+ std::list< Dom* > get_list() const noexcept { return m_list; }
- std::list< Dom* >::iterator begin();
- std::list< Dom* >::reverse_iterator rbegin();
- std::list< Dom* >::iterator end();
- std::list< Dom* >::reverse_iterator rend();
- size_t size() const;
- size_t max_size() const;
- bool empty() const;
+ std::list< Dom* >::iterator begin() noexcept { return m_list.begin(); }
+ std::list< Dom* >::reverse_iterator rbegin() noexcept { return m_list.rbegin(); }
+ std::list< Dom* >::iterator end() noexcept { return m_list.end(); }
+ std::list< Dom* >::reverse_iterator rend() noexcept { return m_list.rend(); }
+ size_t size() const noexcept { return m_list.size(); }
+ size_t max_size() const noexcept { return m_list.max_size(); }
+ bool empty() const noexcept { return m_list.empty(); }
Dom* front(); // front() と back()は参照ではなくポインタを返す
Dom* back();
- void push_front( Dom* dom );
- void push_back( Dom* dom );
- void pop_front();
- void pop_back();
- std::list< Dom* >::iterator insert( std::list< Dom* >::iterator it, Dom* dom );
- std::list< Dom* >::iterator erase( std::list< Dom* >::iterator it );
- void clear();
- void splice( std::list< Dom* >::iterator it, DomList& domlist );
- void remove( Dom* dom );
- void unique();
- void merge( DomList& domlist );
- void sort();
- void reverce();
- void swap( DomList& domlist );
+ void push_front( Dom* dom ){ m_list.push_front( dom ); }
+ void push_back( Dom* dom ){ m_list.push_back( dom ); }
+ void pop_front(){ m_list.pop_front(); }
+ void pop_back(){ m_list.pop_back(); }
+ std::list< Dom* >::iterator insert( std::list< Dom* >::iterator it, Dom* dom ){ return m_list.insert( it, dom ); }
+ std::list< Dom* >::iterator erase( std::list< Dom* >::iterator it ){ return m_list.erase( it ); }
+ void clear(){ m_list.clear(); }
+ void splice( std::list< Dom* >::iterator it, DomList& domlist ){ m_list.splice( it, domlist.m_list ); }
+ void remove( Dom* dom ){ m_list.remove( dom ); }
+ void unique(){ m_list.unique(); }
+ void merge( DomList& domlist ){ m_list.merge( domlist.m_list ); }
+ void sort(){ m_list.sort(); }
+ void reverce(){ m_list.reverse(); }
+ void swap( DomList& domlist ){ m_list.swap( domlist.m_list ); }
};
}
diff --git a/src/xml/tools.cpp b/src/xml/tools.cpp
index 7bdd9f5e..07eead54 100644
--- a/src/xml/tools.cpp
+++ b/src/xml/tools.cpp
@@ -71,6 +71,10 @@ std::string XML::get_name( const int type_id )
name = "linkfilter";
break;
+ case TYPE_REPLACESTR:
+ name = "replacestr";
+ break;
+
case TYPE_SEPARATOR:
name = "separator";
break;
@@ -143,6 +147,10 @@ int XML::get_type( const std::string& node_name )
{
type = TYPE_LINKFILTER;
}
+ else if( node_name == "replacestr" )
+ {
+ type = TYPE_REPLACESTR;
+ }
else if( node_name == "separator" )
{
type = TYPE_SEPARATOR;
@ma8ma
Copy link
Author

ma8ma commented May 30, 2019

初版のパッチは5chログの画像リンクが機能しない不具合があるため一部の修正を取り消した第2版をアップしました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment