From 91e2057151e2089ecade2fa396116b9da786a182 Mon Sep 17 00:00:00 2001 From: ds14050 Date: Mon, 15 Oct 2018 13:35:48 +0900 Subject: [PATCH] =?UTF-8?q?Fix=20#539=20=E3=80=8CTex=E3=81=AE=E3=83=95?= =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=A7=E8=90=BD=E3=81=A1=E3=81=BE?= =?UTF-8?q?=E3=81=99=E3=80=82=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix: トピックの階層が連続しない場合に、トピックが抜けたり、未初期化変数にアクセスして落ちないように。 * Fix: バッファ長より長いトピックタイトルで落ちないように。 * Fix: 3桁以上になる連番で落ちないように。 * Chg: 連番なしのトピックがあるときでも階層が正しくなるように。 --- sakura_core/types/CType_Tex.cpp | 309 +++++++++++++++++++++----------- 1 file changed, 203 insertions(+), 106 deletions(-) diff --git a/sakura_core/types/CType_Tex.cpp b/sakura_core/types/CType_Tex.cpp index 8263d9885c..4250631e6b 100644 --- a/sakura_core/types/CType_Tex.cpp +++ b/sakura_core/types/CType_Tex.cpp @@ -57,126 +57,223 @@ void CType_Tex::InitTypeConfigImp(STypeConfig* pType) @date 2003.07.21 naoh 新規作成 @date 2005.01.03 naoh 「マ」などの"}"を含む文字に対する修正、prosperのslideに対応 */ -void CDocOutline::MakeTopicList_tex(CFuncInfoArr* pcFuncInfoArr) +template +class TagProcessor { - const wchar_t* pLine; - CLogicInt nLineLen; - int i; - int j; - int k; - - const int nMaxStack = 8; // ネストの最深 - int nDepth = 0; // いまのアイテムの深さを表す数値。 - wchar_t szTag[32], szTitle[256]; // 一時領域 - int thisSection=0, lastSection = 0; // 現在のセクション種類と一つ前のセクション種類 - int stackSection[nMaxStack]; // 各深さでのセクションの番号 - int nStartTitlePos = 0; // \section{dddd} の dddd の部分の始まる番号 - int bNoNumber = 0; // * 付の場合はセクション番号を付けない - - // 一行ずつ - CLogicInt nLineCount; - for(nLineCount=CLogicInt(0);nLineCountm_cDocLineMgr.GetLineCount();nLineCount++) + // 環境 + CFuncInfoArr &refFuncInfoArr; + CLayoutMgr &refLayoutMgr; + // 定数 + const wchar_t* (&TagHierarchy)[Size]; + const int HierarchyMax; + // 状態 + int tagDepth; // 直前のタグの深さ。TagHierarchy[tagDepth] == 直前のタグ; + int treeDepth; // 直前のタグの「ツリーにおける」深さ。 + int serials[Size]; // タグの各深さで割り振ったトピック番号の最大値を記憶しておく。 + // 作業場 + wchar_t szTopic[256]; // トピック番号 + トピックタイトル; (タグが * で終わっている場合はトピック番号を省略する) + +public: + TagProcessor(CFuncInfoArr& fia, CLayoutMgr& lmgr, const wchar_t* (&tagHierarchy)[Size]) + : refFuncInfoArr(fia) + , refLayoutMgr(lmgr) + , TagHierarchy(tagHierarchy) + , HierarchyMax(Size-1) + , tagDepth(0) + , treeDepth(-1) + , serials() { - pLine = m_pcDocRef->m_cDocLineMgr.GetLine(nLineCount)->GetDocLineStrWithEOL(&nLineLen); - if(!pLine) break; - // 一文字ずつ - for(i=0;i=nMaxStack)continue; - if(pLine[i] != L'\\')continue; // 「\」がないなら次の文字へ - ++i; - // 見つかった「\」以降の文字列チェック - for(j=0;i+j 0) - { - // sectionの中身取得 - for(k=0;nStartTitlePos+k inline +TagProcessor +MakeTagProcessor(CFuncInfoArr& fia, CLayoutMgr& lmgr, const wchar_t* (&tagHierarchy)[Size]) +{ + return TagProcessor(fia, lmgr, tagHierarchy); +} + +class TagIterator +{ + const CDocLineMgr& refDocLineMgr; + +public: + TagIterator(const CDocLineMgr& dlmgr) + : refDocLineMgr(dlmgr) + {} + + template + void each(TagProcessor& process) + { + const CLogicInt nLineCount = refDocLineMgr.GetLineCount(); + for (CLogicInt nLineLen, nLineNumber = CLogicInt(0); nLineNumber < nLineCount; ++nLineNumber) { + const wchar_t* const pLine = refDocLineMgr.GetLine(nLineNumber)->GetDocLineStrWithEOL(&nLineLen); + const wchar_t* const pLineEnd = pLine + nLineLen; + if (! pLine) { // [EOF] のみの行。 + break; + } + + const wchar_t *pTag = 0, // \section{dddd} または \section*{dddd} の、s を指すポインタ。 + *pTagEnd = 0, // \section{dddd} または \section*{dddd} の、{ または * を指すポインタ。 + *pTitle = 0, // \section{dddd} または \section*{dddd} の、先頭の d を指すポインタ。 + *pTitleEnd = 0; // \section{dddd} または \section*{dddd} の、} を指すポインタ。 + + // 一文字ずつ + for (const wchar_t* p = pLine; p < pLineEnd; ++p) { + if (*p == L'%') { + break; // コメントなので以降はいらない。 } - szTitle[k] = '\0'; - - CLayoutPoint ptPos; - - WCHAR tmpstr[256]; - WCHAR secstr[4]; - - m_pcDocRef->m_cLayoutMgr.LogicToLayout( - CLogicPoint(i, nLineCount), - &ptPos - ); - - int sabunSection = thisSection - lastSection; - if(lastSection == 0){ - nDepth = 0; - stackSection[0] = 1; - }else{ - nDepth += sabunSection; - if(sabunSection > 0){ - if(nDepth >= nMaxStack) nDepth=nMaxStack-1; - stackSection[nDepth] = 1; - }else{ - if(nDepth < 0) nDepth=0; - ++stackSection[nDepth]; - } + if (*p != L'\\') { + continue; // 「\」がないなら次の文字へ。 } - tmpstr[0] = L'\0'; - if(!bNoNumber){ - for(k=0; k<=nDepth; k++){ - auto_sprintf(secstr, L"%d.", stackSection[k]); - wcscat(tmpstr, secstr); - } - wcscat(tmpstr, L" "); + + // '\' の後ろから、'{' を目印にタグとタイトルを見つける。 + pTag = ++p; + p = (p = wmemchr(p, L'{', pLineEnd - p)) ? p : pLineEnd; + pTagEnd = p < pLineEnd ? p++ : pLineEnd; + pTitle = p; + p = (p = wmemchr(p, L'}', pLineEnd - p)) ? p : pLineEnd; + pTitleEnd = p; + + // タグの処理は任せる。 + if (pTag < pTagEnd && pTitle < pTitleEnd) { + p = process(nLineNumber, pLine, pTag, pTagEnd, pTitle, pTitleEnd, pLineEnd); + } + if (p < pTag || pLineEnd < p) { + return; // 無効な値であるか、無限ループのおそれがあるため中断。 } - wcscat(tmpstr, szTitle); - pcFuncInfoArr->AppendData(nLineCount+CLogicInt(1),ptPos.GetY2()+CLayoutInt(1), tmpstr, 0, nDepth); - if(!bNoNumber) lastSection = thisSection; } - i += j; } } +}; + +void CDocOutline::MakeTopicList_tex(CFuncInfoArr* pcFuncInfoArr) +{ + const wchar_t* TagHierarchy[] = { + L"part", + L"chapter", + L"section", + L"subsection", + L"subsubsection", + L"paragraph", + L"subparagraph" + }; + TagIterator(m_pcDocRef->m_cDocLineMgr).each( + MakeTagProcessor(*pcFuncInfoArr, m_pcDocRef->m_cLayoutMgr, TagHierarchy) + ); }