1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5 * Copyright (c) 2011-2016, The OpenClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16 // markup tags for fonts
17
18 #include "C4Include.h"
19 #include "lib/C4Markup.h"
20 #include "graphics/C4BltTransform.h"
21
22 using namespace std::string_literals;
23
OpeningTag() const24 std::string C4MarkupTag::OpeningTag() const
25 {
26 return "<"s + TagName() + ">";
27 }
28
ClosingTag() const29 std::string C4MarkupTag::ClosingTag() const
30 {
31 return "</"s + TagName() + ">";
32 }
33
Apply(C4BltTransform & rBltTrf,bool fDoClr,DWORD & dwClr)34 void C4MarkupTagItalic::Apply(C4BltTransform &rBltTrf, bool fDoClr, DWORD &dwClr)
35 {
36 // do sheering
37 rBltTrf.mat[1]-=0.3f;
38 }
39
Apply(C4BltTransform & rBltTrf,bool fDoClr,DWORD & dwClr)40 void C4MarkupTagColor::Apply(C4BltTransform &rBltTrf, bool fDoClr, DWORD &dwClr)
41 {
42 // set color
43 if (fDoClr) dwClr = this->dwClr;
44 }
45
46
OpeningTag() const47 std::string C4MarkupTagColor::OpeningTag() const
48 {
49 return "<c "s + FormatString("%x", dwClr).getData() + ">";
50 }
51
Read(const char ** ppText,bool fSkip)52 bool C4Markup::Read(const char **ppText, bool fSkip)
53 {
54 char Tag[50]; C4MarkupTag *pNewTag=nullptr; int iTagLen,iParLen;
55 // get tag
56 if (!SCopyEnclosed(*ppText, '<', '>', Tag, 49)) return false;
57 iTagLen=SLen(Tag);
58 // split tag to name and pars
59 char *szPars=nullptr; int iSPos;
60 if ((iSPos=SCharPos(' ', Tag))>-1)
61 {
62 Tag[iSPos]=0;
63 szPars=Tag+iSPos+1;
64 }
65 // closing tag?
66 if (Tag[0]=='/')
67 {
68 // no parameters
69 if (szPars) return false;
70 if (!fSkip)
71 {
72 // is this the tag to be closed?
73 if (!pLast) return false;
74 if (!SEqual(pLast->TagName(), Tag+1)) return false;
75 // close it
76 delete Pop();
77 }
78 }
79 // italic
80 else if (SEqual(Tag, "i"))
81 {
82 // no parameters
83 if (szPars) return false;
84 // create italic tag
85 if (!fSkip) pNewTag=new C4MarkupTagItalic();
86 }
87 // colored
88 else if (SEqual(Tag, "c"))
89 {
90 // no parameters?
91 if (!szPars) return false;
92 if ((iParLen=SLen(szPars))>8) return false;
93 if (!fSkip)
94 {
95 // get color value by parameter
96 DWORD dwClr=0;
97 for (int i=0; i<iParLen; ++i)
98 {
99 BYTE b;
100 if (szPars[i]>='0' && szPars[i]<='9') b=szPars[i]-'0';
101 else if (szPars[i]>='a' && szPars[i]<='f') b=szPars[i]-'a'+10;
102 else return false;
103 dwClr|=(b<<((iParLen-i-1)*4));
104 }
105 // adjust alpha if not given
106 if (iParLen<=6) dwClr|=0xff000000;
107 // create color tag
108 pNewTag=new C4MarkupTagColor(dwClr);
109 }
110 }
111 // unknown tag
112 else return false;
113 // add created tag
114 if (pNewTag) Push(pNewTag);
115 // advance past tag
116 *ppText+=iTagLen+2;
117 // success
118 return true;
119 }
120
121
122
SkipTags(const char ** ppText)123 bool C4Markup::SkipTags(const char **ppText)
124 {
125 // read tags as long as found
126 while (**ppText=='<') if (!Read(ppText, true)) break;
127 // return whether end is reached
128 return !**ppText;
129 }
130
131
ClosingTags() const132 std::string C4Markup::ClosingTags() const
133 {
134 std::string result;
135 for (auto tag = pLast; tag; tag = tag->pPrev)
136 result += tag->ClosingTag();
137 return result;
138 }
139
OpeningTags() const140 std::string C4Markup::OpeningTags() const
141 {
142 std::string result;
143 for (auto tag = pTags; tag; tag = tag->pNext)
144 result += tag->OpeningTag();
145 return result;
146 }
147
StripMarkup(char * szText)148 bool C4Markup::StripMarkup(char *szText)
149 {
150 // skip any tags and inline-images
151 C4Markup mkup(false);
152 const char *szRead = szText, *szPos2;
153 do
154 {
155 mkup.SkipTags(&szRead);
156 if (szRead[0] == '{' && szRead[1] == '{' && szRead[2] != '{') // skip at {{{, because {{{id}} should be parsed as { {{id}} }.
157 {
158 if ((szPos2 = SSearch(szRead+2, "}}")))
159 // valid {{blub}}-tag
160 szRead = szPos2;
161 else
162 // invalid {{-tag
163 szRead += 2;
164 }
165 else if (szRead[0] == '}' && szRead[1] == '}')
166 // invalid }}-tag
167 szRead += 2;
168 }
169 while ((*szText++ = *szRead++));
170 return szText != szRead;
171 }
172
StripMarkup(StdStrBuf * sText)173 bool C4Markup::StripMarkup(StdStrBuf *sText)
174 {
175 // strip any markup codes from given text buffer
176 char *buf = sText->GrabPointer();
177 if (!buf) return false;
178 bool fSuccess = StripMarkup(buf);
179 sText->Take(buf);
180 return fSuccess;
181 }
182