-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathApus.Engine.ComplexText.pas
More file actions
131 lines (120 loc) · 3.5 KB
/
Apus.Engine.ComplexText.pas
File metadata and controls
131 lines (120 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Complex text is a text string where characters has different attributes, such as
// font (including size and style), color, fill (background color) and link attribute
// Complex text can be stored in different forms including HTML-style simplified markup language (SML)
// This unit contains wide set of routines for manipulation with complex text strings
//
// Copyright (C) 2015 Ivan Polyacov, Apus Software (ivan@apus-software.com)
// This file is licensed under the terms of BSD-3 license (see license.txt)
// This file is a part of the Apus Game Engine (http://apus-software.com/engine/)
unit Apus.Engine.ComplexText;
interface
uses Apus.Common;
// SML routines
// ------------
// Returns number of plain text characters in SML string
function SMLLength(st:WideString):integer;
// Returns plain text from the SML string
function SMLExtract(st:WideString):WideString;
function SMLExtractUTF8(st:AnsiString):AnsiString; // UTF-8 version
// Build index for the string ([plain text character index] -> SML character index)
function SMLIndex(st:WideString):IntArray;
function SMLGetLinkAt(st:WideString;index:integer):cardinal;
implementation
function SMLLength(st:WideString):integer;
var
index:IntArray;
begin
index:=SMLIndex(st);
result:=high(index);
end;
function SMLGetLinkAt(st:WideString;index:integer):cardinal;
var
tagMode:boolean;
i,n,len:integer;
vst:string[8];
stack:array[0..9] of cardinal;
stackPos:integer;
v:cardinal;
begin
result:=0;
tagMode:=false;
i:=1; n:=1;
stackpos:=0;
v:=0;
len:=length(st);
while i<=len do begin
if not tagmode then begin
if n=index then result:=v;
if (st[i]='{') and (i<len) then begin
if st[i+1] in ['!','/','B','b','I','i','U','u','C','c','G','g','L','l','F','f'] then tagMode:=true
else inc(n);
if st[i+1]='{' then inc(i);
end else
inc(n);
end else begin
if st[i]='}' then tagmode:=false;
if (st[i]='/') and (i<len) and (st[i+1] in ['l','L']) then begin
if stackpos>0 then begin
dec(stackPos); v:=stack[stackPos];
end else v:=0;
end;
if (st[i] in ['L','l']) and (i<len+2) and (st[i+1]='=') then begin
vst:=''; inc(i,2);
while (i<=len) and (st[i] in ['0'..'9','a'..'f','A'..'F']) do begin
vst:=vst+st[i]; inc(i);
end;
dec(i);
stack[stackPos]:=v; inc(stackPos);
v:=HexToInt(vst);
end;
end;
inc(i);
end;
end;
function SMLIndex(st:WideString):IntArray;
var
i,len,cnt:integer;
tagmode:boolean;
begin
tagmode:=false;
len:=length(st);
SetLength(result,len+1);
i:=1; cnt:=0;
while i<=len do begin
if tagmode then begin
// inside {}
case st[i] of
'}':tagmode:=false;
end;
end else begin
// outside {}
if (st[i]='{') and (i<len-1) and
(st[i+1] in ['!','/','B','b','I','i','U','u','C','c','G','g','L','l','F','f']) then begin
tagmode:=true;
end else begin
inc(cnt);
result[cnt]:=i;
if (st[i]='{') and (i<len) and (st[i+1]='{') then inc(i);
end;
end;
inc(i);
end;
result[0]:=cnt;
SetLength(result,cnt+1);
end;
function SMLExtract(st:WideString):WideString;
var
i,len,cnt:integer;
tagmode:boolean;
index:IntArray;
begin
index:=SMLIndex(st);
SetLength(result,high(index));
for i:=1 to high(index) do
result[i]:=st[index[i]];
end;
function SMLExtractUTF8(st:AnsiString):AnsiString;
begin
result:=EncodeUTF8(SMLExtract(DecodeUTF8(st)),false);
end;
end.