/* * $Id: GLSDImportModuleAdapter.cpp,v 1.19 2006/07/13 13:31:18 ozawa Exp $ * * Copyright 2005- ONGS Inc. All rights reserved. * * author: Masanori OZAWA (ozawa@ongs.co.jp) * version: $Revision: 1.19 $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY ONGS INC ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL ONGS INC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the ONGS Inc. * */ #include "xdtp.h" #include "modules/imports/GLSDImportModuleAdapter.h" #include "URI.h" #include "URLTool.h" #include "Utilities.h" #include "XMLTool.h" #define TIP_TAG "___XDTP_GLSD_IMPORT_TAG___" using namespace XDTP; GLSDImportModuleAdapter::GLSDImportModuleAdapter() { m_OutputType = DEFAULT_OUTPUT_TYPE; m_OutputEncoding = DEFAULT_OUTPUT_ENCODING; m_pXDTPTransform = NULL; } GLSDImportModuleAdapter::~GLSDImportModuleAdapter() { } /** * 現在のXDTPTransformモジュールを取得します。 * * @return 現在のXDTPTransformモジュール */ const XDTPTransform * GLSDImportModuleAdapter::getXDTPTransform() { return m_pXDTPTransform; } /** * 処理を開始する前に出力形式を設定します。 * * @param aType 出力形式 */ void GLSDImportModuleAdapter::setOutputType(const Glib::ustring& aType) { m_OutputType = aType; } /** * 処理を開始する前にオプションを設定します。 * * @param anOptions オプション */ void GLSDImportModuleAdapter::setOption(const StringList& anOptions) { m_OptionList = anOptions; } /** * 処理を開始する前に出力ファイル名を設定します。 * * @param anOutputFile 出力ファイル名 */ void GLSDImportModuleAdapter::setOutputFile(const Glib::ustring& anOutputFile) { m_OutputFile = anOutputFile; } /** * 処理を開始する前に変換元XMLファイル名を設定します。 * * @param aXMLFile 変換元XMLファイル名 */ void GLSDImportModuleAdapter::setXMLFile(const Glib::ustring& aXMLFile) { m_XMLFile = aXMLFile; } /** * 入力ファイルのエンコードを指定します。 * XMLファイルはこの限りではありません。 * * @param anInputEncoding 入力ファイルのエンコード */ void GLSDImportModuleAdapter::setInputEncoding(const Glib::ustring& anInputEncoding) { m_InputEncoding = anInputEncoding; } /** * 出力ファイルのエンコードを指定します。 * * @param anOutputEncoding 出力ファイルのエンコード */ void GLSDImportModuleAdapter::setOutputEncoding(const Glib::ustring& anOutputEncoding) { m_OutputEncoding = anOutputEncoding; } /** * 現在のXDTPTransformモジュールを指定します。 * * @param aXDTPTransform 現在のXDTPTransformモジュール */ void GLSDImportModuleAdapter::setXDTPTransform(const XDTPTransform *aXDTPTransform) { m_pXDTPTransform = aXDTPTransform; } /** * XMLファイルのエンコーディングを指定します。 * * @param anEncoding XMLファイルのエンコーディング */ void GLSDImportModuleAdapter::setXMLEncoding(const std::string& anEncoding) { m_XMLEncoding = anEncoding; } /** * ファイルをparseする直前に呼び出されます。 * * @param aFile parse対象のファイル名 */ void GLSDImportModuleAdapter::treatPreFile(const Glib::ustring& aFile) { // no operation } /** * parseしたXML文章をXSL変換する直前に呼び出されます。 * * @param aDocument XML文章 */ void GLSDImportModuleAdapter::treatPreDocument(xmlDocPtr aDocument) { // no operation } /** * XSL変換後のXML文章を保存する直前に呼び出されます。 * * @param aDocument XML文章 */ void GLSDImportModuleAdapter::treatPostDocument(xmlDocPtr aDocument) { // no operation } /** * XML文章を保存した直後に呼び出されます。 * * @param aFile 保存したファイル名 */ void GLSDImportModuleAdapter::treatPostFile(const Glib::ustring& aFile) { // no operation } /** * ファイルからインポート処理対象の部分を抽出し、置換処理を * 行う際に呼び出されます。 * * @param aRef インポート先のファイル * @param aCaption キャプション * @param anEncoding インポート先のファイルのエンコード * @param aNewData 置換すべき文字列を応答します。 * @return 処理結果を応答します。 */ TIP_STATUS GLSDImportModuleAdapter::transformImportPointCallback (const Glib::ustring& aRef, const Glib::ustring& aCaption, const Glib::ustring& anEncoding, Glib::ustring& aNewData) { return TIP_SKIP; } /** * インポート処理対象を識別するノードを構築します。 * * @param aType 処理対象の種類 * @param aRef インポート先のファイル * @param aCaption キャプション * @param anEncoding インポート先のファイルのエンコード * @return インポート処理対象を識別するノード */ xmlNodePtr GLSDImportModuleAdapter::createNewImportPointNode (const Glib::ustring& aType, const Glib::ustring& aRef, const Glib::ustring& aCaption, const Glib::ustring& anEncoding) { Glib::ustring comment = TIP_TAG LINE_SEP; comment += "type=" + aType + LINE_SEP; comment += "ref=" + aRef + LINE_SEP; comment += "caption=" + aCaption + LINE_SEP; comment += "encoding=" + anEncoding + LINE_SEP; return xmlNewComment((const xmlChar*)comment.c_str()); } /** * ファイルからインポート処理対象の部分を抽出し、置換処理を行います。 * * @param aFile 処理対象のファイル * @param aType 処理対象の種類 * @return 成功した場合は true を戻します。 */ bool GLSDImportModuleAdapter::transformImportPoint (const Glib::ustring& aFile, const Glib::ustring& aType) { bool result = false; // 一時ファイルを構築 std::string tmpfile = "_xdtp_temp.XXXXXX"; int fd = Glib::mkstemp(tmpfile); if (0 > fd) { fprintf(stderr, "%s: Unable to create temp file." LINE_SEP, APP_NAME); return false; } close(fd); // インポート置換処理 try { Glib::ustring line, data, newdata; Glib::ustring type, ref, caption, encoding; Glib::ustring::size_type pos, posRet; Glib::RefPtr iioc = Glib::IOChannel::create_from_file(aFile.c_str(), "r"); Glib::RefPtr oioc = Glib::IOChannel::create_from_file(tmpfile.c_str(), "w"); iioc->set_encoding(m_OutputEncoding); oioc->set_encoding(m_OutputEncoding); while (iioc->read_line(line) == Glib::IO_STATUS_NORMAL) { pos = line.find(""); if (Glib::ustring::npos != pos) { data += line.substr(0, pos +3); break; } data += line; } if (Glib::ustring::npos == pos) THROW("Unable to find the terminate position of import."); line = line.substr(pos +3); pos = data.find("type="); posRet = data.find(LINE_SEP, pos); if (Glib::ustring::npos == pos || Glib::ustring::npos == posRet) { THROW("Internal error!"); } pos += 5; type = data.substr(pos, posRet - pos); pos = data.find("ref="); posRet = data.find(LINE_SEP, pos); if (Glib::ustring::npos == pos || Glib::ustring::npos == posRet) { THROW("Internal error!"); } pos += 4; ref = data.substr(pos, posRet - pos); pos = data.find("caption="); posRet = data.find(LINE_SEP, pos); if (Glib::ustring::npos == pos || Glib::ustring::npos == posRet) { THROW("Internal error!"); } pos += 8; caption = data.substr(pos, posRet - pos); pos = data.find("encoding="); posRet = data.find(LINE_SEP, pos); if (Glib::ustring::npos == pos || Glib::ustring::npos == posRet) { THROW("Internal error!"); } pos += 9; encoding = data.substr(pos, posRet - pos); if (type == aType) { newdata = ""; switch (transformImportPointCallback(ref, caption, encoding, newdata)) { case TIP_SUCCESS: oioc->write(newdata); break; case TIP_SKIP: oioc->write(data); break; default: case TIP_FAILED: THROW("Unable to transform the import point."); break; } } else { oioc->write(data); } } oioc->write(line); } iioc->close(); oioc->close(); result = true; } catch (Exception exception) { exception.print(stderr); } catch (Glib::Error error) { std::string msg = Glib::locale_from_utf8(error.what()); fprintf(stderr, "%s: %s" LINE_SEP, APP_NAME, msg.c_str()); } catch (std::exception exception) { fprintf(stderr, "%s: %s" LINE_SEP, APP_NAME, exception.what()); } catch (...) { fprintf(stderr, "%s: ImportTextSourcecode: unknown error occured." LINE_SEP, APP_NAME); } if (result) { result = Utilities::move(tmpfile, aFile); } if (!result) { remove(tmpfile.c_str()); } return result; } /** * 任意タイプのスタイルシートを取得する。 * * @param aDocument * XHTMLドキュメント * @param aType * スタイルシートのタイプ * 常に小文字で指定する必要があります。 * @return 取得したスタイルシート */ xmlNodePtr GLSDImportModuleAdapter::getStyleSheet (xmlDocPtr aDocument, const Glib::ustring& aType) { if (0 >= aType.length()) { THROW("bad arguments."); } // スタイルシートのエレメントを取得 int count; XMLTool tool; xmlNodePtr comment = NULL; xmlNodePtr node; xmlNodePtr root = xmlDocGetRootElement(aDocument); xmlNodeSetPtr nodes; xmlXPathObjectPtr obj = tool.getNodeList(root, "/html/head/style"); const char *pTmp; Glib::ustring value; if (obj) { nodes = obj->nodesetval; for (count = 0; count < nodes->nodeNr; count++) { node = nodes->nodeTab[count]; pTmp = (const char*)xmlGetProp(node, (const xmlChar*)"type"); value = (pTmp ? pTmp : ""); if (pTmp) xmlFree((xmlChar*)pTmp); value = value.lowercase(); if (value == aType) { break; } } if (count < nodes->nodeNr) { // スタイルシートのコメント部を取得 for (node = node->children; node; node = node->next) { if (tool.isComment(node)) { comment = node; break; } } } xmlXPathFreeObject(obj); } // 取得できない場合は新規に作成する if (!comment) { xmlNodePtr style = NULL; obj = tool.getNodeList(root, "/html/head/style"); if (obj) { nodes = obj->nodesetval; for (count = 0; count < nodes->nodeNr; count++) { pTmp = (const char*)xmlGetProp(nodes->nodeTab[count], (const xmlChar*)"type"); value = (pTmp ? pTmp : ""); if (pTmp) xmlFree((xmlChar*)pTmp); value = value.lowercase(); if (value == aType) { style = nodes->nodeTab[count]; break; } } xmlXPathFreeObject(obj); } if (!style) { obj = tool.getNodeList(root, "/html/head"); if (!obj) return NULL; nodes = obj->nodesetval; node = nodes->nodeTab[0]; xmlXPathFreeObject(obj); style = xmlNewNode(NULL, (const xmlChar*)"style"); xmlSetProp(style, (const xmlChar*)"type", (const xmlChar*)aType.c_str()); xmlAddChild(node, style); } if (!style) THROW("Out of memory!"); comment = xmlNewComment((const xmlChar*)""); if (!comment) THROW("Out of memory!"); xmlAddChild(style, comment); } return comment; } /** * Importタグの各種属性値を取得します。 * * @param aNode Importノード * @param aRef リソースのURL * @param aCaption キャプション * @param anEncoding リソースのエンコーディング * @return 取得に成功した場合は true を戻す。 */ bool GLSDImportModuleAdapter::getImportAttributes(xmlNodePtr aNode, Glib::ustring& aRef, Glib::ustring& aCaption, Glib::ustring& anEncoding) { const char *pRef = (const char*)xmlGetProp(aNode, (const xmlChar*)"ref"); if (!pRef) return false; const char *pCaption = (const char*)xmlGetProp(aNode, (const xmlChar*)"caption"); const char *pEncoding = (const char*)xmlGetProp(aNode, (const xmlChar*)"encoding"); aRef = Utilities::strTrim(pRef); aCaption = Utilities::strTrim((pCaption ? pCaption : "")); anEncoding = Utilities::strTrim((pEncoding ? pEncoding : "")); xmlFree((xmlChar*)pRef); if (pCaption) xmlFree((xmlChar*)pCaption); if (pEncoding) xmlFree((xmlChar*)pEncoding); if (getenv(XDTP_URI_TRANSITION)) { // 誤ったURIを修正する RefPtr uri = URI::parse(aRef); aRef = uri->toString().c_str(); } return true; } /** * URIで参照するリソースへのIOChannelを取得します。 * 取得できない場合は XDTP::Exception を throw します。 * * @param aRef URI * @param aTmpFile 一時ファイルを生成した場合は、一時ファイルへのパスを応答します。 * 生成しない場合は、空文字列を応答します。 * @return リソースへのIOChannel */ Glib::RefPtr GLSDImportModuleAdapter::getIOChannel (const Glib::ustring& aRef, std::string& aTmpFile) { Glib::RefPtr result; try { std::string target; RefPtr uri = URI::parse(normalizeURL(aRef)); if (0 >= uri->getScheme().length() || uri->isFileScheme()) { target = uri->getPath(); } else { aTmpFile = "_xdtp_temp.XXXXXX"; int fd = Glib::mkstemp(aTmpFile); if (0 > fd) { aTmpFile = ""; THROW("Unable to create temp file."); } if (!URLTool::getResource2File(aRef, fd)) { close(fd); THROW("Unable to read the resource. " + aRef); } close(fd); target = aTmpFile; } result = Glib::IOChannel::create_from_file(target.c_str(), "r"); } catch (Exception exception) { THROW(exception.what() + " (" + aRef + ")"); } catch (Glib::Error error) { std::string msg = Glib::locale_from_utf8(error.what()); THROW(msg + " (" + aRef + ")"); } catch (std::exception exception) { std::string msg = exception.what(); THROW(msg + " (" + aRef + ")"); } catch (...) { THROW("GLSDImportModuleAdapter: Unknown error occured. (" + aRef + ")"); } return result; } /** * ローカルファイルを参照するURLを絶対パスのURLに展開する。 */ Glib::ustring GLSDImportModuleAdapter::normalizeURL(const Glib::ustring& url) { bool froceFileScheme = false; RefPtr uri = URI::parse(url); Glib::ustring result = url; if (0 >= uri->getScheme().length()) { if (0 >= url.length() || (2 <= url.length() && "//" == url.substr(0, 2))) { THROW("Bad URI. (" + url + ")"); } froceFileScheme = true; } if (froceFileScheme || uri->isFileScheme()) { if (0 >= uri->getPath().length()) { // パスが存在しないURLはエラーとする。 if (7 < url.length() && "file://" == url.substr(0, 7).lowercase()) { THROW("Bad URL. (" + url + ")" LINE_SEP "\tThis problem may be able to be solved by setting up" LINE_SEP "\tenvironment variable XDTP_URI_TRANSITION."); } THROW("Bad URL. (" + url + ")"); } else if (!Glib::path_is_absolute(uri->getPath())) { result = uri->getPath(); Glib::ustring::size_type pos = m_XMLFile.rfind(FILE_SEP); if (Glib::ustring::npos != pos) { result = m_XMLFile.substr(0, pos) + FILE_SEP + result; #ifdef WIN32 result = Utilities.strReplaceAll(result, FILE_SEP, "/"); #endif } if (!Glib::path_is_absolute(result)) { result = Glib::build_filename(Glib::get_current_dir(), result); } result = "file:" + result; } } return result; } /** * ファイルの読み込み用エンコードを適切に設定する。 * * @param anIOC エンコードを設定するIOChannel * @param aDocument XMLドキュメント * @param anEncoding 優先的に設定するエンコード。不明な場合は空文字列を指定する。 */ void GLSDImportModuleAdapter::setEncoding(Glib::RefPtr& anIOC, const Glib::ustring& anEncoding) { if (!anEncoding.empty()) { anIOC->set_encoding(anEncoding); } else if (!m_InputEncoding.empty()) { anIOC->set_encoding(m_InputEncoding); } else if (!m_XMLEncoding.empty()) { anIOC->set_encoding(m_XMLEncoding); } else { std::string encoding; Glib::get_charset(encoding); anIOC->set_encoding(encoding.c_str()); } } /** * XMLドキュメント用に特殊文字をエスケープします。 * * @param aString 特殊文字を含む文字列 * @return エスケープ後の文字列 */ Glib::ustring GLSDImportModuleAdapter::escapeString(const Glib::ustring& aString) { // エスケープ処理 Glib::ustring result =aString; result = Utilities::strReplaceAll(result, "&", "&"); // & result = Utilities::strReplaceAll(result, "<", "<"); // < result = Utilities::strReplaceAll(result, ">", ">"); // > result = Utilities::strReplaceAll(result, " ", " "); // スペース result = Utilities::strReplaceAll(result, "\\", "\"); // バックスラッシュ return result; } /** * Importタグをテキスト形式で保持します。 */ bool GLSDImportModuleAdapter::preserveImport(xmlDocPtr aDocument, xmlNodePtr aNode, const Glib::ustring& aRef, const Glib::ustring& aCaption, const Glib::ustring& anEncoding) { const char *pType = (const char*)xmlGetProp(aNode, (const xmlChar*)"type"); Glib::ustring type = (pType ? pType : ""); Glib::ustring text = ""; if (pType) xmlFree((xmlChar*)pType); xmlNodePtr import = xmlNewText((const xmlChar*)text.c_str()); if (!import) return false; xmlFreeNode(xmlReplaceNode(aNode, import)); return true; } /** * 指定のキーで識別されるオプションの値を取得します。 * * @param aKey オプションを一意に識別する値 * @param aValue 取得したオプションの値を格納する領域 * @return オプションが見付かり正しく取得できた場合は true を戻します。 */ bool GLSDImportModuleAdapter::getOptionInt(const Glib::ustring& aKey, int &aValue) { long val = 0; char *endptr = NULL; Glib::ustring tmp; if (getOptionString(aKey, tmp) && 0 < tmp.length()) { val = strtol(tmp.c_str(), &endptr, 10); if ('\0' == *endptr) { aValue = (int)val; return true; } } return false; } bool GLSDImportModuleAdapter::getOptionString(const Glib::ustring& aKey, Glib::ustring& aValue) { bool result = false; Glib::ustring key = aKey + "="; StringList::const_iterator iter = m_OptionList.begin(); StringList::const_iterator end = m_OptionList.end(); for (; iter != end; iter++) { if (key.length() <= iter->length() && key.compare(iter->substr(0, key.length())) == 0) { aValue = iter->substr(key.length()); result = true; break; } } return result; }