OSDN Git Service

TPI内部でのパスのハードコーディングを撤廃。
[tpi/lychee.git] / src / plugin / cuiWrapper / cuiWrapper.cpp
index 42aec89..1ee4032 100644 (file)
 //    Includes\r
 //******************************************************************************\r
 \r
+#define MYUSE_LIBPATH 1\r
 #include "../../common/header/plugin.h"\r
 #include "../../common/header/plugin-extra.h"\r
 #include "../../common/library/library.h"\r
 #include "../../common/library/xmldoc.h"\r
 #include <wx/tokenzr.h>\r
-#include <wx/process.h>\r
-#include <wx/txtstrm.h>\r
 #include "cuiWrapper.h"\r
+#define min(a, b) ((a) < (b) ? (a) : (b))\r
 \r
 //******************************************************************************\r
 //    Global varients\r
@@ -51,30 +51,83 @@ TPI_PROC g_prProc;
 //    Inside Functions\r
 //******************************************************************************\r
 \r
-int myExecute(const wxString & szCommandLine, bool fWine)\r
+int myExecute(const wxString & szCommandLine, wxString * szOutput, const wxString & szCwd, bool fWine)\r
 {\r
 #ifdef __LINUX__\r
+       wxString sz = ::wxGetCwd();\r
+       ::wxSetWorkingDirectory(szCwd);\r
        FILE * fp = popen(fWine ? (wxT("wine ") + szCommandLine).ToUTF8() : szCommandLine.ToUTF8(), "r");\r
+       ::wxSetWorkingDirectory(sz);\r
        if (fp == NULL)\r
        {\r
                wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());\r
                return TPI_ERROR_U_USE_LIBRARY;\r
        }\r
 \r
+       if (szOutput != NULL)\r
+       {\r
+               char sz[32769];\r
+               while (! feof(fp))\r
+               {\r
+                       memset(sz, 0, sizeof(sz));\r
+                       fread(sz, sizeof(char), sizeof(sz) - 1, fp);\r
+                       * szOutput += UTF82String(sz);\r
+               }\r
+//             ::wxMessageBox(* szOutput);\r
+       }\r
+\r
        // 127を返した場合はコマンドが存在しない。\r
        int nErrorCode = pclose(fp);\r
        return (WIFEXITED(nErrorCode) && WEXITSTATUS(nErrorCode) != 127) ? TPI_ERROR_SUCCESS : TPI_ERROR_U_USE_LIBRARY;\r
 #else\r
+       SECURITY_ATTRIBUTES sa;\r
+       memset(& sa, 0, sizeof(SECURITY_ATTRIBUTES));\r
+       sa.bInheritHandle = TRUE;\r
+       sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
+       HANDLE hRead, hWrite;\r
+       if (! ::CreatePipe(& hRead, & hWrite, & sa, 4096))\r
+       {\r
+               return TPI_ERROR_U_USE_LIBRARY;\r
+       }\r
        STARTUPINFO si;\r
-       PROCESS_INFORMATION pi;\r
        memset(& si, 0, sizeof(STARTUPINFO));\r
        si.cb = sizeof(STARTUPINFO);\r
-       if (! ::CreateProcess(NULL, szCommandLine.wchar_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, & si, & pi))\r
+       si.dwFlags = STARTF_USESTDHANDLES;\r
+       si.hStdOutput = hWrite;\r
+       si.hStdError = hWrite;\r
+       PROCESS_INFORMATION pi;\r
+       if (! ::CreateProcess(NULL, szCommandLine.wchar_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, szCwd.IsEmpty() ? NULL : szCwd.wchar_str(), & si, & pi))\r
        {\r
                return TPI_ERROR_U_USE_LIBRARY;\r
        }\r
        ::CloseHandle(pi.hThread);\r
+\r
+       if (szOutput != NULL)\r
+       {\r
+               bool bSignal;\r
+               do\r
+               {\r
+                       DWORD dwSize = 0;\r
+                       bSignal = ::WaitForSingleObject(pi.hProcess, 100) == WAIT_OBJECT_0;\r
+                       ::PeekNamedPipe(hRead, NULL, 0, NULL, & dwSize, NULL);\r
+                       while (dwSize > 0)\r
+                       {\r
+                               char sz[4097];\r
+                               memset(sz, 0, sizeof(sz));\r
+                               ::ReadFile(hRead, & sz, sizeof(sz) - 1, & dwSize, NULL);\r
+                               * szOutput += wxString(sz);\r
+                               // UTF-8以外の文字コードだと、UTF82Stringを使うと書庫が開けなくなる。データの切り出しにも影響。\r
+//                             * szOutput += UTF82String(sz);\r
+//                             ::MessageBoxA(NULL, sz, NULL, 0);\r
+                               ::PeekNamedPipe(hRead, NULL, 0, NULL, & dwSize, NULL);\r
+                       }\r
+               }\r
+               while (! bSignal);\r
+       }\r
+\r
        ::CloseHandle(pi.hProcess);\r
+       ::CloseHandle(hRead);\r
+       ::CloseHandle(hWrite);\r
        return TPI_ERROR_SUCCESS;\r
 #endif\r
 }\r
@@ -88,18 +141,15 @@ PosInfo MakePosInfo(const wxString & szPrefix)
        return pi;\r
 }\r
 \r
-wxULongLong_t GetSize(const PosInfo & pi, const wxArrayString & as)\r
+wxULongLong_t GetSize(const PosInfo & pi, wxULongLong_t nCurrent, const wxArrayString & as)\r
 {\r
        if (pi.nStart == 0 && pi.nCount == 0)\r
        {\r
                return 0;\r
        }\r
 \r
-       wxULongLong_t nTemp = 0;\r
-       wxString sz =\r
-               pi.nCount == 0 ?\r
-                       as[pi.nLine].Mid(pi.nStart) :\r
-                       as[pi.nLine].Mid(pi.nStart, pi.nCount);\r
+       wxULongLong_t nTemp = 0, nPos = nCurrent + pi.nLine;\r
+       wxString sz = pi.nCount == 0 ? as[nPos].Mid(pi.nStart) : as[nPos].Mid(pi.nStart, pi.nCount);\r
        sz.ToULongLong(& nTemp);\r
        return nTemp;\r
 }\r
@@ -133,6 +183,9 @@ int __stdcall GetPluginInformation
        case TPI_INFO_VERSION_API:\r
                * (int *) _pPtr = 2;\r
                break;\r
+       case TPI_INFO_HANDLE_ON_COMMAND:\r
+               * (int *) _pPtr = 0;\r
+               break;\r
        default:\r
                return TPI_ERROR_D_UNSUPPORTED;\r
        }\r
@@ -162,7 +215,7 @@ int __stdcall GetFormatInformation(TPI_FORMATINFO * _fiInfo, bool _bFirst)
 \r
        MakeFormatInfo(xmlLibrary, wxT("cuiWrapper"), _fiInfo, s_nFileId++);\r
        wxString szExeFile = xmlLibrary->GetAttribute(wxT("name"), wxEmptyString);\r
-       if (myExecute(szExeFile, szExeFile.EndsWith(wxT(".exe"))) != TPI_ERROR_SUCCESS)\r
+       if (myExecute(szExeFile, NULL, wxEmptyString, szExeFile.MakeLower().EndsWith(wxT(".exe"))) != TPI_ERROR_SUCCESS)\r
        {\r
                _fiInfo->eSupportedCommand = 0;\r
        }\r
@@ -172,6 +225,7 @@ int __stdcall GetFormatInformation(TPI_FORMATINFO * _fiInfo, bool _bFirst)
 int __stdcall LoadPlugin\r
 (\r
        const wxString & _szArcName,\r
+       TPI_PROC _prProc,\r
        wxULongLong_t _nTypeId\r
 )\r
 {\r
@@ -179,6 +233,12 @@ int __stdcall LoadPlugin
        wxXmlDocument xmlDoc(myMakeXMLName(wxT("cuiWrapper")));\r
        wxXmlNode * xmlLibrary;\r
 \r
+       // コールバック関数を設定。\r
+       if (_prProc != NULL)\r
+       {\r
+               g_prProc = * _prProc;\r
+       }\r
+\r
        // 対象が存在するならば対応するライブラリを調査、\r
        // 対象が存在しないならば指示されたライブラリをロード。\r
        if (! ::wxFileExists(_szArcName))\r
@@ -209,7 +269,7 @@ int __stdcall LoadPlugin
                        {\r
                                // .tar.XXXなど二重判定への対応。\r
 //                             if (asExt[i].IsSameAs(fnArchive.GetExt(), false))\r
-                               if (fnArchive.GetFullName().EndsWith(wxT('.') + asExt[i]))\r
+                               if (fnArchive.GetFullName().MakeLower().EndsWith(wxT('.') + asExt[i].MakeLower()))\r
                                {\r
                                        // ライブラリをロード。\r
                                        g_LibInfo.szExeFile = xmlLibrary->GetAttribute(wxT("name"), wxEmptyString);\r
@@ -237,47 +297,43 @@ int __stdcall OpenArchive
 (\r
        const wxString & _szArcName,\r
        void * * _hArchive,\r
-       wxULongLong_t *\r
+       wxULongLong_t * _nFileCount\r
 )\r
 {\r
-       wxString szCommandLine = g_LibInfo.szExeFile + wxT(" ") + MakeCommandLineSend(g_LibInfo.node.GetAttribute(wxT("list"), wxEmptyString), _szArcName);\r
-#ifdef __LINUX__\r
-       wxProcess * p = ::wxProcess::Open(g_LibInfo.szExeFile.EndsWith(wxT(".exe")) ? (wxT("wine ") + szCommandLine) : szCommandLine, wxEXEC_ASYNC);\r
-#else\r
-       wxProcess * p = ::wxProcess::Open(szCommandLine, wxEXEC_ASYNC);\r
-#endif\r
-       if (p == NULL)\r
+       wxString szOutput;\r
+       TPI_SWITCHES swInfo;\r
+       swInfo.szArcName = _szArcName;\r
+       if (myExecute(g_LibInfo.szExeFile + wxT(" ") + MakeCommandLineSend(g_LibInfo.node.GetAttribute(wxT("list"), wxEmptyString), & swInfo), & szOutput, wxEmptyString, g_LibInfo.szExeFile.MakeLower().EndsWith(wxT(".exe"))) != TPI_ERROR_SUCCESS)\r
        {\r
-               wxLogError(L"Error :\n\nCommandLine:\n%s", szCommandLine.c_str());\r
                return TPI_ERROR_U_USE_LIBRARY;\r
        }\r
+       wxArrayString * as = new wxArrayString(::wxStringTokenize(szOutput, wxT("\r\n")));\r
+       * _hArchive = (void *) as;\r
+       as->Shrink();\r
+       if (_nFileCount != NULL)\r
+       {\r
+               * _nFileCount = as->GetCount();\r
+       }\r
 \r
-       p->Redirect();\r
-       wxInputStream * is = p->GetInputStream();\r
-       wxTextInputStream tis(* is);\r
        wxString szStartLine = g_LibInfo.node.GetAttribute(wxT("list-line-s"), wxEmptyString);\r
-       if (! szStartLine.IsEmpty())\r
+       if ((! szStartLine.IsEmpty() && as->Index(szStartLine) == wxNOT_FOUND) || as->IsEmpty())\r
        {\r
-               // 開始行まで読み飛ばす。\r
-               while (! is->Eof() && tis.ReadLine() != szStartLine);\r
-               if (is->Eof())\r
-               {\r
-                       // 書庫が読み込めなかった?\r
-                       ::wxSafeShowMessage(wxEmptyString, wxT("Unsupported archive!"));\r
-                       p->Detach();\r
-                       return TPI_ERROR_ARC_UNSUPPORTED;\r
-               }\r
+               // 書庫が読み込めなかった?\r
+               delete as;\r
+               return TPI_ERROR_ARC_UNSUPPORTED;\r
        }\r
 \r
-       * _hArchive = (void *) is;\r
-       return is->Eof() ? TPI_ERROR_UNDEFINED : TPI_ERROR_SUCCESS;\r
+       return TPI_ERROR_SUCCESS;\r
 }\r
 \r
 int __stdcall CloseArchive\r
 (\r
-       void *\r
+       void * _hArchive\r
 )\r
 {\r
+       wxArrayString * as = (wxArrayString *) _hArchive;\r
+       as->Clear();\r
+       delete as;\r
        return TPI_ERROR_SUCCESS;\r
 }\r
 \r
@@ -294,8 +350,7 @@ int __stdcall GetFileInformation
        {\r
                return TPI_ERROR_UNDEFINED;\r
        }\r
-       wxInputStream * is = (wxInputStream *) _hArchive;\r
-       wxTextInputStream tis(* is);\r
+       wxArrayString asOutput = * (wxArrayString *) _hArchive;\r
 \r
        // XMLからの読み込みは初回に行う。\r
        static wxString szEndLine, szDateFormat;\r
@@ -303,60 +358,55 @@ int __stdcall GetFileInformation
        static PosInfo piFName, piPSize, piUSize, piDate;\r
        if (_bFirst)\r
        {\r
-               // 初期設定。\r
                s_nFileId = 0;\r
+               wxString szStartLine = g_LibInfo.node.GetAttribute(wxT("list-line-s"), wxEmptyString);\r
+               if (! szStartLine.IsEmpty())\r
+               {\r
+                       // 開始行の次の行にセット。エラーはOpenArchiveでチェック済み。\r
+                       s_nCurrentLine = asOutput.Index(szStartLine) + 1;\r
+               }\r
+\r
+               // 初期設定。\r
                nProcessPerLine = myGetAttributeInt(& g_LibInfo.node, wxT("list-line-c"), 1);\r
-               szEndLine       = g_LibInfo.node.GetAttribute(wxT("list-line-e"), g_LibInfo.node.GetAttribute(wxT("list-line-s"), wxEmptyString));\r
-               szDateFormat    = g_LibInfo.node.GetAttribute(wxT("list-date-f"), wxDefaultDateTimeFormat);\r
+               szEndLine = g_LibInfo.node.GetAttribute(wxT("list-line-e"), szStartLine);\r
+               szDateFormat = g_LibInfo.node.GetAttribute(wxT("list-date-f"), wxDefaultDateTimeFormat);\r
                piFName = MakePosInfo(wxT("fname"));\r
                piPSize = MakePosInfo(wxT("psize"));\r
                piUSize = MakePosInfo(wxT("usize"));\r
                piDate  = MakePosInfo(wxT("date"));\r
        }\r
 \r
-       if (is->Eof())\r
+       if (s_nCurrentLine >= asOutput.GetCount())\r
        {\r
                // 空行で終わるとき以外はエラーとする。\r
                return szEndLine.IsEmpty() ? TPI_ERROR_S_ENDOFDATA : TPI_ERROR_ARC_UNSUPPORTED;\r
        }\r
 \r
-       // 必要な行数だけ取得。\r
-       wxArrayString as;\r
-       as.Add(tis.ReadLine());\r
-       if (as[0] == szEndLine)\r
+       // 最終行かどうか確認。\r
+       if (asOutput[s_nCurrentLine] == szEndLine)\r
        {\r
                return TPI_ERROR_S_ENDOFDATA;\r
        }\r
-       for (int i = 1; i < nProcessPerLine; i++)\r
-       {\r
-               as.Add(tis.ReadLine());\r
-       }\r
 \r
        // ファイル名を取得。\r
-       _fiInfo->szStoredName =\r
-               piFName.nCount == 0 ?\r
-                       as[piFName.nLine].Mid(piFName.nStart) :\r
-                       as[piFName.nLine].Mid(piFName.nStart, piFName.nCount);\r
+       _fiInfo->szStoredName = piFName.nCount == 0 ? asOutput[s_nCurrentLine + piFName.nLine].Mid(piFName.nStart) : asOutput[s_nCurrentLine + piFName.nLine].Mid(piFName.nStart, piFName.nCount);\r
        _fiInfo->szStoredName.Trim();\r
        _fiInfo->fnFileName = wxFileName(_fiInfo->szStoredName, wxPATH_DOS);\r
 \r
        // サイズ取得。\r
-       _fiInfo->nPackedSize   = GetSize(piPSize, as);\r
-       _fiInfo->nUnpackedSize = GetSize(piUSize, as);\r
+       _fiInfo->nPackedSize   = GetSize(piPSize, s_nCurrentLine, asOutput);\r
+       _fiInfo->nUnpackedSize = GetSize(piUSize, s_nCurrentLine, asOutput);\r
 \r
        // 更新時刻取得。\r
        if (piDate.nStart != 0 || piDate.nCount != 0)\r
        {\r
-               _fiInfo->tmModify.ParseFormat(\r
-                       piDate.nCount == 0 ?\r
-                               as[piDate.nLine].Mid(piDate.nStart) :\r
-                               as[piDate.nLine].Mid(piDate.nStart, piDate.nCount),\r
-                       szDateFormat\r
-               );\r
+               _fiInfo->tmModify.ParseFormat(piDate.nCount == 0 ? asOutput[s_nCurrentLine + piDate.nLine].Mid(piDate.nStart) : asOutput[s_nCurrentLine + piDate.nLine].Mid(piDate.nStart, piDate.nCount), szDateFormat);\r
        }\r
 \r
        // 最後に次の行へ進めておく。\r
        _fiInfo->nFileId = s_nFileId++;\r
+       s_nCurrentLine += nProcessPerLine;\r
+\r
        return TPI_ERROR_SUCCESS;\r
 }\r
 \r
@@ -375,7 +425,7 @@ int __stdcall Command
 (\r
        wxULongLong_t _eCommand,\r
        TPI_SWITCHES * _swInfo,\r
-       const wxString & _szArcName,\r
+       void *,// _hArchive,\r
        const wxArrayString & _szFiles\r
 )\r
 {\r
@@ -416,72 +466,20 @@ int __stdcall Command
        // コマンドライン・レスポンスファイル作成。\r
        wxString\r
                szResponceFileName = MakeResponceFile(_szFiles, myGetAttributeBool(& g_LibInfo.node, wxT("quote-resp"), true)),\r
-               szCommandLineSend  = g_LibInfo.szExeFile + wxT(" ") + MakeCommandLineSend(szCommandLine, _szArcName, _swInfo, _szFiles, szResponceFileName),\r
-               sz = ::wxGetCwd();\r
+               szCommandLineSend  = MakeCommandLineSend(szCommandLine, _swInfo, _szFiles, szResponceFileName);\r
 \r
        // コマンドライン実行。\r
-       ::wxSetWorkingDirectory(_swInfo->fnDestinationDirectory.GetFullPath());\r
-#ifdef __LINUX__\r
-       wxProcess * p = ::wxProcess::Open(g_LibInfo.szExeFile.EndsWith(wxT(".exe")) ? (wxT("wine ") + szCommandLineSend) : szCommandLineSend, wxEXEC_ASYNC);\r
-#else\r
-       wxProcess * p = ::wxProcess::Open(szCommandLineSend, wxEXEC_ASYNC);\r
-#endif\r
-       ::wxSetWorkingDirectory(sz);\r
-       if (p == NULL)\r
-       {\r
-               ::wxRemoveFile(szResponceFileName);\r
-               wxLogError(L"CommandLine:\n%s", szCommandLineSend.c_str());\r
-               return TPI_ERROR_U_USE_LIBRARY;\r
-       }\r
-\r
-       TPI_PROCESSINFO piInfo;\r
-       piInfo.eMessage = TPI_MESSAGE_STATUS;\r
-       piInfo.eStatus = TPI_STATUS_INPROCESS;\r
-       piInfo.nProcessedSize = 0;\r
-\r
-       p->Redirect();\r
        wxString szOutput;\r
-       wxInputStream * is = p->GetInputStream();\r
-       while (! is->Eof())\r
-       {\r
-               // コールバック関数に送信。\r
-               if (g_prProc != NULL && g_prProc(TPI_NOTIFY_COMMON, & piInfo) == TPI_CALLBACK_CANCEL)\r
-               {\r
-                       p->Kill(p->GetPid(), wxSIGKILL);\r
-                       p->Detach();\r
-                       ::wxRemoveFile(szResponceFileName);\r
-                       return TPI_ERROR_D_SKIPPED;\r
-               }\r
-\r
-               if (! is->CanRead())\r
-               {\r
-                       continue;\r
-               }\r
-\r
-               char sz[8192];\r
-               is->Read(sz, sizeof(sz));\r
-               szOutput += UTF82String(sz);\r
-       }\r
-//     ::wxMessageBox(szOutput);\r
+       int nErrorCode = myExecute(g_LibInfo.szExeFile + wxT(" ") + szCommandLineSend, & szOutput, _swInfo->fnDestinationDirectory.GetFullPath(), g_LibInfo.szExeFile.MakeLower().EndsWith(wxT(".exe")));\r
 \r
        // レスポンスファイル削除。\r
        ::wxRemoveFile(szResponceFileName);\r
-       return TPI_ERROR_SUCCESS;\r
-}\r
 \r
-int __stdcall SetCallbackProc\r
-(\r
-       TPI_PROC _prArcProc\r
-)\r
-{\r
-       // ポインタを保存。\r
-       if (_prArcProc == NULL)\r
+       if (nErrorCode != TPI_ERROR_SUCCESS)\r
        {\r
-               return TPI_ERROR_D_PARAMETER;\r
+               wxLogError(L"Error :\n%x\n\nCommandLine:\n%s\n\nOutput:\n%s", nErrorCode, szCommandLineSend.c_str(), szOutput.c_str());\r
        }\r
-       g_prProc = * _prArcProc;\r
-\r
-       return TPI_ERROR_SUCCESS;\r
+       return nErrorCode;\r
 }\r
 \r
 #ifdef __cplusplus\r