├── README.md
├── STHTMLPP.sln
├── STHTMLPP
├── HtmlAgilityPack.h
├── STHTMLPP.cpp
├── STHTMLPP.vcxproj
├── STHTMLPP.vcxproj.filters
├── STHTMLPP.vcxproj.user
├── Source.def
├── Tools.h
├── sds.c
├── sds.h
├── stdafx.cpp
├── stdafx.h
├── strings.h
├── targetver.h
├── utf8_strings.cpp
└── utf8_strings.h
└── img
├── 123.PNG
└── 456.PNG
/README.md:
--------------------------------------------------------------------------------
1 | # gumbo-querySelector
2 | html选择器elss
3 |
4 | 
5 |
6 | 
7 |
8 | 于解析引擎无关的表达式解析引擎elss
9 |
10 |
11 | elss 0.0.1
12 | 2018/09/25 17:57:00 修订
13 | 人员:
14 | 开发:海绵宝宝
15 | 语法:我才是星辰
16 | 吹牛逼的:二毛娃娃
17 |
18 |
19 | 语法组成:指令
20 |
21 | 3大基本语法:标签名 .class值 #id值
22 |
23 | 基本指令 > :
24 |
25 | 多条指令使用语法:指令1 > 指令2 > 指令3 > ...
26 |
27 | 基本语法规范:
28 | ----------------------------------------------------
29 | 字符串和属性使用单引号或者双引号引起来
30 | ----------------------------------------------------
31 |
32 |
33 | 基本函数:
34 | ----------------------------------------------------
35 | find(属性,内容) 为查找属性值为内容的标签
36 | fuzzyfind(属性,内容) 为查找属性值包含内容的标签
37 | ----------------------------------------------------
38 |
39 |
40 | 基本功能1:
41 | ----------------------------------------------------
42 | 说明:我想获取a标签的所有内容
43 |
44 | 1
45 | 2
46 | 3
47 |
48 | 指令:a
49 | ----------------------------------------------------
50 |
51 | 基本功能2:
52 | ----------------------------------------------------
53 | 说明:我想获取id为list1的div里面的a标签的所有内容
54 |
55 |
56 |
57 | -
58 | 1
59 |
60 | -
61 | 2
62 |
63 | -
64 | 3
65 |
66 |
67 |
68 |
69 |
70 | -
71 | 4
72 |
73 | -
74 | 5
75 |
76 | -
77 | 6
78 |
79 |
80 |
81 |
82 |
83 | 指令1:#list1 > dl > dd > a
84 | 或
85 | 指令2:div:find('id','list1') > dl > dd > a
86 | ----------------------------------------------------
87 |
88 | 功能1:
89 | ----------------------------------------------------
90 | 说明:指令前面是. 则为匹配class属性,要匹配出233
91 |
92 | 233
93 |
94 | 指令:.test
95 | ----------------------------------------------------
96 |
97 |
98 | 功能2:
99 | ----------------------------------------------------
100 | 说明:指令前面是# 则为匹配id属性,要匹配出233
101 |
102 | 233
103 |
104 | 指令:#test
105 | ----------------------------------------------------
106 |
107 |
108 | 功能3:
109 | ----------------------------------------------------
110 | 说明:如果想指定标签属性筛选,要匹配出233
111 |
112 | 233
113 | 266
114 |
115 | 指令:div:find('id','test')
116 | ----------------------------------------------------
117 |
118 |
119 | 功能4:
120 | ----------------------------------------------------
121 | 说明:如果想指定标签属性模糊筛选,要匹配出233和266
122 |
123 | 233
124 | 266
125 |
126 | 指令:div:fuzzyfind('id','test_')
127 | ----------------------------------------------------
128 |
129 | 功能5:
130 | ----------------------------------------------------
131 | 支持函数链式操作
132 | div:find('id','test'):div:fuzzyfind('id','test_')>div>a
133 | 支持以上所有语法混合
134 | div:find('id','test'):div>fuzzyfind('id','test_')
135 |
136 | ----------------------------------------------------
137 |
138 |
139 | qq群交流:551518556
140 |
--------------------------------------------------------------------------------
/STHTMLPP.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2010
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "STHTMLPP", "STHTMLPP\STHTMLPP.vcxproj", "{0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Debug|x64.ActiveCfg = Debug|x64
17 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Debug|x64.Build.0 = Debug|x64
18 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Debug|x86.ActiveCfg = Debug|Win32
19 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Debug|x86.Build.0 = Debug|Win32
20 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Release|x64.ActiveCfg = Release|x64
21 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Release|x64.Build.0 = Release|x64
22 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Release|x86.ActiveCfg = Release|Win32
23 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {E1C4CE25-55F8-4739-B16D-8F7CFC0D181D}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/STHTMLPP/HtmlAgilityPack.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/STHTMLPP/HtmlAgilityPack.h
--------------------------------------------------------------------------------
/STHTMLPP/STHTMLPP.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/STHTMLPP/STHTMLPP.cpp
--------------------------------------------------------------------------------
/STHTMLPP/STHTMLPP.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {0E7FE817-E488-4F4D-ADB9-14BCD9317ABA}
24 | Win32Proj
25 | STHTMLPP
26 | 10.0.16299.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v141
33 | Unicode
34 | Static
35 | false
36 |
37 |
38 | DynamicLibrary
39 | false
40 | v141_xp
41 | true
42 | MultiByte
43 | Static
44 |
45 |
46 | Application
47 | true
48 | v141
49 | Unicode
50 |
51 |
52 | DynamicLibrary
53 | false
54 | v141_xp
55 | true
56 | MultiByte
57 | Static
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | true
79 | D:\用户目录\下载\htmlgumbo-parser-master\gumbo-parser-master\src;C:\Users\海绵宝宝\source\repos\libicon\Release;$(IncludePath)
80 | C:\Users\海绵宝宝\source\repos\libicon\Release;$(LibraryPath)
81 |
82 |
83 | true
84 |
85 |
86 | false
87 | C:\Users\海绵宝宝\source\repos\ATLProject1\Debug;C:\Users\海绵宝宝\source\repos\libicon\Release;$(IncludePath)
88 | C:\Users\海绵宝宝\source\repos\ATLProject1\Debug;C:\Users\海绵宝宝\source\repos\libiconv-1.15-3-vc15-x86\lib;C:\Users\海绵宝宝\source\repos\libicon\Release;$(LibraryPath)
89 | HtmlAgilityPack
90 |
91 |
92 | false
93 | HtmlAgilityPack
94 | D:\用户目录\下载\htmlgumbo-parser-master\gumbo-parser-master\src;D:\用户目录\下载\htmlgumbo-parser-master\gumbo-parser-master\visualc\include;C:\Users\海绵宝宝\source\repos\libicon\Release;$(IncludePath)
95 | D:\用户目录\下载\htmlgumbo-parser-master\gumbo-parser-master\src;C:\Users\海绵宝宝\source\repos\libiconv-1.15-3-vc15-x86\lib;C:\Users\海绵宝宝\source\repos\libicon\Release;$(LibraryPath)
96 |
97 |
98 |
99 | NotUsing
100 | Level3
101 | Disabled
102 | true
103 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 | false
105 | false
106 |
107 |
108 | Console
109 | true
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | Use
119 | Level3
120 | Disabled
121 | true
122 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
123 | true
124 |
125 |
126 | Console
127 | true
128 |
129 |
130 |
131 |
132 | NotUsing
133 | Level3
134 | Disabled
135 | true
136 | true
137 | true
138 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
139 | false
140 | MultiThreaded
141 |
142 |
143 | Console
144 | true
145 | true
146 | true
147 | Source.def
148 | %(AdditionalDependencies)
149 |
150 |
151 |
152 |
153 | NotUsing
154 | Level3
155 | MaxSpeed
156 | true
157 | true
158 | true
159 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
160 | true
161 |
162 |
163 | Console
164 | true
165 | true
166 | true
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 | Create
211 | Create
212 | Create
213 | Create
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
--------------------------------------------------------------------------------
/STHTMLPP/STHTMLPP.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
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 | 源文件
132 |
133 |
134 | 源文件
135 |
136 |
137 |
138 |
139 | 源文件
140 |
141 |
142 | 源文件
143 |
144 |
145 | 源文件
146 |
147 |
148 |
--------------------------------------------------------------------------------
/STHTMLPP/STHTMLPP.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/STHTMLPP/Source.def:
--------------------------------------------------------------------------------
1 | LIBRARY STHTMLPP
2 | EXPORTS
3 | Find
4 | Find1
5 | CreateHtml
6 | LoadHtml
7 | engineFree
8 | GetNode
9 | GetNodeSize
10 | GetNodeText
11 | GetNodeHtml
12 | GetAttr
13 | GetRootNode
14 | engineClose
15 | GetNodeFree
--------------------------------------------------------------------------------
/STHTMLPP/Tools.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/STHTMLPP/Tools.h
--------------------------------------------------------------------------------
/STHTMLPP/sds.c:
--------------------------------------------------------------------------------
1 | /* SDSLib, A C dynamic strings library
2 | *
3 | * Copyright (c) 2006-2012, Salvatore Sanfilippo
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include "sds.h"
37 | sds sdsnewlen(const void *init, size_t initlen) {
38 | struct sdshdr *sh;
39 |
40 | if (init) {
41 | sh = malloc(sizeof(struct sdshdr) + initlen + 1);
42 | }
43 | else {
44 | sh = calloc(1, sizeof(struct sdshdr) + initlen + 1);
45 | }
46 | if (sh == NULL) return NULL;
47 | sh->len = initlen;
48 | sh->free = 0;
49 | if (initlen && init)
50 | memcpy(sh->buf, init, initlen);
51 | sh->buf[initlen] = '\0';
52 | return (char*)sh->buf;
53 | }
54 |
55 | sds sdsempty(void) {
56 | return sdsnewlen("", 0);
57 | }
58 |
59 | sds sdsnew(const char *init) {
60 | size_t initlen = (init == NULL) ? 0 : strlen(init);
61 | return sdsnewlen(init, initlen);
62 | }
63 |
64 | sds sdsdup(const sds s) {
65 | return sdsnewlen(s, sdslen(s));
66 | }
67 |
68 | void sdsfree(sds s) {
69 | if (s == NULL) return;
70 | void* sa = s - sizeof(struct sdshdr);
71 | free(sa);
72 | }
73 |
74 | void sdsupdatelen(sds s) {
75 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
76 | int reallen = strlen(s);
77 | sh->free += (sh->len - reallen);
78 | sh->len = reallen;
79 | }
80 |
81 | void sdsclear(sds s) {
82 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
83 | sh->free += sh->len;
84 | sh->len = 0;
85 | sh->buf[0] = '\0';
86 | }
87 |
88 | /* Enlarge the free space at the end of the sds string so that the caller
89 | * is sure that after calling this function can overwrite up to addlen
90 | * bytes after the end of the string, plus one more byte for nul term.
91 | *
92 | * Note: this does not change the *size* of the sds string as returned
93 | * by sdslen(), but only the free buffer space we have. */
94 | sds sdsMakeRoomFor(sds s, size_t addlen) {
95 | struct sdshdr *sh, *newsh;
96 | size_t free = sdsavail(s);
97 | size_t len, newlen;
98 |
99 | if (free >= addlen) return s;
100 | len = sdslen(s);
101 | sh = (void*)(s - (sizeof(struct sdshdr)));
102 | newlen = (len + addlen);
103 | if (newlen < SDS_MAX_PREALLOC)
104 | newlen *= 2;
105 | else
106 | newlen += SDS_MAX_PREALLOC;
107 | newsh = realloc(sh, sizeof(struct sdshdr) + newlen + 1);
108 | if (newsh == NULL) return NULL;
109 |
110 | newsh->free = newlen - len;
111 | return newsh->buf;
112 | }
113 |
114 | /* Reallocate the sds string so that it has no free space at the end. The
115 | * contained string remains not altered, but next concatenation operations
116 | * will require a reallocation. */
117 | sds sdsRemoveFreeSpace(sds s) {
118 | struct sdshdr *sh;
119 |
120 | sh = (void*)(s - (sizeof(struct sdshdr)));
121 | sh = realloc(sh, sizeof(struct sdshdr) + sh->len + 1);
122 | sh->free = 0;
123 | return sh->buf;
124 | }
125 |
126 | size_t sdsAllocSize(sds s) {
127 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
128 |
129 | return sizeof(*sh) + sh->len + sh->free + 1;
130 | }
131 |
132 | /* Increment the sds length and decrements the left free space at the
133 | * end of the string accordingly to 'incr'. Also set the null term
134 | * in the new end of the string.
135 | *
136 | * This function is used in order to fix the string length after the
137 | * user calls sdsMakeRoomFor(), writes something after the end of
138 | * the current string, and finally needs to set the new length.
139 | *
140 | * Note: it is possible to use a negative increment in order to
141 | * right-trim the string.
142 | *
143 | * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
144 | * following schema to cat bytes coming from the kernel to the end of an
145 | * sds string new things without copying into an intermediate buffer:
146 | *
147 | * oldlen = sdslen(s);
148 | * s = sdsMakeRoomFor(s, BUFFER_SIZE);
149 | * nread = read(fd, s+oldlen, BUFFER_SIZE);
150 | * ... check for nread <= 0 and handle it ...
151 | * sdsIncrLen(s, nhread);
152 | */
153 | void sdsIncrLen(sds s, int incr) {
154 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
155 |
156 | assert(sh->free >= incr);
157 | sh->len += incr;
158 | sh->free -= incr;
159 | assert(sh->free >= 0);
160 | s[sh->len] = '\0';
161 | }
162 |
163 | /* Grow the sds to have the specified length. Bytes that were not part of
164 | * the original length of the sds will be set to zero. */
165 | sds sdsgrowzero(sds s, size_t len) {
166 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
167 | size_t totlen, curlen = sh->len;
168 |
169 | if (len <= curlen) return s;
170 | s = sdsMakeRoomFor(s, len - curlen);
171 | if (s == NULL) return NULL;
172 |
173 | /* Make sure added region doesn't contain garbage */
174 | sh = (void*)(s - (sizeof(struct sdshdr)));
175 | memset(s + curlen, 0, (len - curlen + 1)); /* also set trailing \0 byte */
176 | totlen = sh->len + sh->free;
177 | sh->len = len;
178 | sh->free = totlen - sh->len;
179 | return s;
180 | }
181 |
182 | sds sdscatlen(sds s, const void *t, size_t len) {
183 | struct sdshdr *sh;
184 | size_t curlen = sdslen(s);
185 |
186 | s = sdsMakeRoomFor(s, len);
187 | if (s == NULL) return NULL;
188 | sh = (void*)(s - (sizeof(struct sdshdr)));
189 | memcpy(s + curlen, t, len);
190 | sh->len = curlen + len;
191 | sh->free = sh->free - len;
192 | s[curlen + len] = '\0';
193 | return s;
194 | }
195 |
196 | sds sdscat(sds s, const char *t) {
197 | return sdscatlen(s, t, strlen(t));
198 | }
199 |
200 | sds sdscatsds(sds s, const sds t) {
201 | return sdscatlen(s, t, sdslen(t));
202 | }
203 |
204 | sds sdscpylen(sds s, const char *t, size_t len) {
205 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
206 | size_t totlen = sh->free + sh->len;
207 |
208 | if (totlen < len) {
209 | s = sdsMakeRoomFor(s, len - sh->len);
210 | if (s == NULL) return NULL;
211 | sh = (void*)(s - (sizeof(struct sdshdr)));
212 | totlen = sh->free + sh->len;
213 | }
214 | memcpy(s, t, len);
215 | s[len] = '\0';
216 | sh->len = len;
217 | sh->free = totlen - len;
218 | return s;
219 | }
220 |
221 | sds sdscpy(sds s, const char *t) {
222 | return sdscpylen(s, t, strlen(t));
223 | }
224 |
225 | sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
226 | va_list cpy;
227 | char *buf, *t;
228 | size_t buflen = 16;
229 |
230 | while (1) {
231 | buf = malloc(buflen);
232 | if (buf == NULL) return NULL;
233 | buf[buflen - 2] = '\0';
234 | va_copy(cpy, ap);
235 | vsnprintf(buf, buflen, fmt, cpy);
236 | if (buf[buflen - 2] != '\0') {
237 | free(buf);
238 | buflen *= 2;
239 | continue;
240 | }
241 | break;
242 | }
243 | t = sdscat(s, buf);
244 | free(buf);
245 | return t;
246 | }
247 |
248 | sds sdscatprintf(sds s, const char *fmt, ...) {
249 | va_list ap;
250 | char *t;
251 | va_start(ap, fmt);
252 | t = sdscatvprintf(s, fmt, ap);
253 | va_end(ap);
254 | return t;
255 | }
256 |
257 | sds sdstrim(sds s, const char *cset) {
258 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
259 | char *start, *end, *sp, *ep;
260 | size_t len;
261 |
262 | sp = start = s;
263 | ep = end = s + sdslen(s) - 1;
264 | while (sp <= end && strchr(cset, *sp)) sp++;
265 | while (ep > start && strchr(cset, *ep)) ep--;
266 | len = (sp > ep) ? 0 : ((ep - sp) + 1);
267 | if (sh->buf != sp) memmove(sh->buf, sp, len);
268 | sh->buf[len] = '\0';
269 | sh->free = sh->free + (sh->len - len);
270 | sh->len = len;
271 | return s;
272 | }
273 |
274 | sds sdsrange(sds s, int start, int end) {
275 | struct sdshdr *sh = (void*)(s - (sizeof(struct sdshdr)));
276 | size_t newlen, len = sdslen(s);
277 |
278 | if (len == 0) return s;
279 | if (start < 0) {
280 | start = len + start;
281 | if (start < 0) start = 0;
282 | }
283 | if (end < 0) {
284 | end = len + end;
285 | if (end < 0) end = 0;
286 | }
287 | newlen = (start > end) ? 0 : (end - start) + 1;
288 | if (newlen != 0) {
289 | if (start >= (signed)len) {
290 | newlen = 0;
291 | }
292 | else if (end >= (signed)len) {
293 | end = len - 1;
294 | newlen = (start > end) ? 0 : (end - start) + 1;
295 | }
296 | }
297 | else {
298 | start = 0;
299 | }
300 | if (start && newlen) memmove(sh->buf, sh->buf + start, newlen);
301 | sh->buf[newlen] = 0;
302 | sh->free = sh->free + (sh->len - newlen);
303 | sh->len = newlen;
304 | return s;
305 | }
306 |
307 | void sdstolower(sds s) {
308 | int len = sdslen(s), j;
309 |
310 | for (j = 0; j < len; j++) s[j] = tolower(s[j]);
311 | }
312 |
313 | void sdstoupper(sds s) {
314 | int len = sdslen(s), j;
315 |
316 | for (j = 0; j < len; j++) s[j] = toupper(s[j]);
317 | }
318 |
319 | int sdscmp(const sds s1, const sds s2) {
320 | size_t l1, l2, minlen;
321 | int cmp;
322 |
323 | l1 = sdslen(s1);
324 | l2 = sdslen(s2);
325 | minlen = (l1 < l2) ? l1 : l2;
326 | cmp = memcmp(s1, s2, minlen);
327 | if (cmp == 0) return l1 - l2;
328 | return cmp;
329 | }
330 |
331 | /* Split 's' with separator in 'sep'. An array
332 | * of sds strings is returned. *count will be set
333 | * by reference to the number of tokens returned.
334 | *
335 | * On out of memory, zero length string, zero length
336 | * separator, NULL is returned.
337 | *
338 | * Note that 'sep' is able to split a string using
339 | * a multi-character separator. For example
340 | * sdssplit("foo_-_bar","_-_"); will return two
341 | * elements "foo" and "bar".
342 | *
343 | * This version of the function is binary-safe but
344 | * requires length arguments. sdssplit() is just the
345 | * same function but for zero-terminated strings.
346 | */
347 | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
348 | int elements = 0, slots = 5, start = 0, j;
349 | sds *tokens;
350 |
351 | if (seplen < 1 || len < 0) return NULL;
352 |
353 | tokens = malloc(sizeof(sds)*slots);
354 | if (tokens == NULL) return NULL;
355 |
356 | if (len == 0) {
357 | *count = 0;
358 | return tokens;
359 | }
360 | for (j = 0; j < (len - (seplen - 1)); j++) {
361 | /* make sure there is room for the next element and the final one */
362 | if (slots < elements + 2) {
363 | sds *newtokens;
364 |
365 | slots *= 2;
366 | newtokens = realloc(tokens, sizeof(sds)*slots);
367 | if (newtokens == NULL) goto cleanup;
368 | tokens = newtokens;
369 | }
370 | /* search the separator */
371 | if ((seplen == 1 && *(s + j) == sep[0]) || (memcmp(s + j, sep, seplen) == 0)) {
372 | tokens[elements] = sdsnewlen(s + start, j - start);
373 | if (tokens[elements] == NULL) goto cleanup;
374 | elements++;
375 | start = j + seplen;
376 | j = j + seplen - 1; /* skip the separator */
377 | }
378 | }
379 | /* Add the final element. We are sure there is room in the tokens array. */
380 | tokens[elements] = sdsnewlen(s + start, len - start);
381 | if (tokens[elements] == NULL) goto cleanup;
382 | elements++;
383 | *count = elements;
384 | return tokens;
385 |
386 | cleanup:
387 | {
388 | int i;
389 | for (i = 0; i < elements; i++) sdsfree(tokens[i]);
390 | free(tokens);
391 | *count = 0;
392 | return NULL;
393 | }
394 | }
395 |
396 | void sdsfreesplitres(sds *tokens, int count) {
397 | if (!tokens) return;
398 | while (count--)
399 | sdsfree(tokens[count]);
400 | free(tokens);
401 | }
402 |
403 | sds sdsfromlonglong(long long value) {
404 | char buf[32], *p;
405 | unsigned long long v;
406 |
407 | v = (value < 0) ? -value : value;
408 | p = buf + 31; /* point to the last character */
409 | do {
410 | *p-- = '0' + (v % 10);
411 | v /= 10;
412 | } while (v);
413 | if (value < 0) *p-- = '-';
414 | p++;
415 | return sdsnewlen(p, 32 - (p - buf));
416 | }
417 |
418 | sds sdscatrepr(sds s, const char *p, size_t len) {
419 | s = sdscatlen(s, "\"", 1);
420 | while (len--) {
421 | switch (*p) {
422 | case '\\':
423 | case '"':
424 | s = sdscatprintf(s, "\\%c", *p);
425 | break;
426 | case '\n': s = sdscatlen(s, "\\n", 2); break;
427 | case '\r': s = sdscatlen(s, "\\r", 2); break;
428 | case '\t': s = sdscatlen(s, "\\t", 2); break;
429 | case '\a': s = sdscatlen(s, "\\a", 2); break;
430 | case '\b': s = sdscatlen(s, "\\b", 2); break;
431 | default:
432 | if (isprint(*p))
433 | s = sdscatprintf(s, "%c", *p);
434 | else
435 | s = sdscatprintf(s, "\\x%02x", (unsigned char)*p);
436 | break;
437 | }
438 | p++;
439 | }
440 | return sdscatlen(s, "\"", 1);
441 | }
442 |
443 | /* Helper function for sdssplitargs() that returns non zero if 'c'
444 | * is a valid hex digit. */
445 | int is_hex_digit(char c) {
446 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
447 | (c >= 'A' && c <= 'F');
448 | }
449 |
450 | /* Helper function for sdssplitargs() that converts an hex digit into an
451 | * integer from 0 to 15 */
452 | int hex_digit_to_int(char c) {
453 | switch (c) {
454 | case '0': return 0;
455 | case '1': return 1;
456 | case '2': return 2;
457 | case '3': return 3;
458 | case '4': return 4;
459 | case '5': return 5;
460 | case '6': return 6;
461 | case '7': return 7;
462 | case '8': return 8;
463 | case '9': return 9;
464 | case 'a': case 'A': return 10;
465 | case 'b': case 'B': return 11;
466 | case 'c': case 'C': return 12;
467 | case 'd': case 'D': return 13;
468 | case 'e': case 'E': return 14;
469 | case 'f': case 'F': return 15;
470 | default: return 0;
471 | }
472 | }
473 |
474 | /* Split a line into arguments, where every argument can be in the
475 | * following programming-language REPL-alike form:
476 | *
477 | * foo bar "newline are supported\n" and "\xff\x00otherstuff"
478 | *
479 | * The number of arguments is stored into *argc, and an array
480 | * of sds is returned.
481 | *
482 | * The caller should free the resulting array of sds strings with
483 | * sdsfreesplitres().
484 | *
485 | * Note that sdscatrepr() is able to convert back a string into
486 | * a quoted string in the same format sdssplitargs() is able to parse.
487 | *
488 | * The function returns the allocated tokens on success, even when the
489 | * input string is empty, or NULL if the input contains unbalanced
490 | * quotes or closed quotes followed by non space characters
491 | * as in: "foo"bar or "foo'
492 | */
493 | sds *sdssplitargs(const char *line, int *argc) {
494 | const char *p = line;
495 | char *current = NULL;
496 | char **vector = NULL;
497 |
498 | *argc = 0;
499 | while (1) {
500 | /* skip blanks */
501 | while (*p && isspace(*p)) p++;
502 | if (*p) {
503 | /* get a token */
504 | int inq = 0; /* set to 1 if we are in "quotes" */
505 | int insq = 0; /* set to 1 if we are in 'single quotes' */
506 | int done = 0;
507 |
508 | if (current == NULL) current = sdsempty();
509 | while (!done) {
510 | if (inq) {
511 | if (*p == '\\' && *(p + 1) == 'x' &&
512 | is_hex_digit(*(p + 2)) &&
513 | is_hex_digit(*(p + 3)))
514 | {
515 | unsigned char byte;
516 |
517 | byte = (hex_digit_to_int(*(p + 2)) * 16) +
518 | hex_digit_to_int(*(p + 3));
519 | current = sdscatlen(current, (char*)&byte, 1);
520 | p += 3;
521 | }
522 | else if (*p == '\\' && *(p + 1)) {
523 | char c;
524 |
525 | p++;
526 | switch (*p) {
527 | case 'n': c = '\n'; break;
528 | case 'r': c = '\r'; break;
529 | case 't': c = '\t'; break;
530 | case 'b': c = '\b'; break;
531 | case 'a': c = '\a'; break;
532 | default: c = *p; break;
533 | }
534 | current = sdscatlen(current, &c, 1);
535 | }
536 | else if (*p == '"') {
537 | /* closing quote must be followed by a space or
538 | * nothing at all. */
539 | if (*(p + 1) && !isspace(*(p + 1))) goto err;
540 | done = 1;
541 | }
542 | else if (!*p) {
543 | /* unterminated quotes */
544 | goto err;
545 | }
546 | else {
547 | current = sdscatlen(current, p, 1);
548 | }
549 | }
550 | else if (insq) {
551 | if (*p == '\\' && *(p + 1) == '\'') {
552 | p++;
553 | current = sdscatlen(current, "'", 1);
554 | }
555 | else if (*p == '\'') {
556 | /* closing quote must be followed by a space or
557 | * nothing at all. */
558 | if (*(p + 1) && !isspace(*(p + 1))) goto err;
559 | done = 1;
560 | }
561 | else if (!*p) {
562 | /* unterminated quotes */
563 | goto err;
564 | }
565 | else {
566 | current = sdscatlen(current, p, 1);
567 | }
568 | }
569 | else {
570 | switch (*p) {
571 | case ' ':
572 | case '\n':
573 | case '\r':
574 | case '\t':
575 | case '\0':
576 | done = 1;
577 | break;
578 | case '"':
579 | inq = 1;
580 | break;
581 | case '\'':
582 | insq = 1;
583 | break;
584 | default:
585 | current = sdscatlen(current, p, 1);
586 | break;
587 | }
588 | }
589 | if (*p) p++;
590 | }
591 | /* add the token to the vector */
592 | vector = realloc(vector, ((*argc) + 1) * sizeof(char*));
593 | vector[*argc] = current;
594 | (*argc)++;
595 | current = NULL;
596 | }
597 | else {
598 | /* Even on empty input string return something not NULL. */
599 | if (vector == NULL) vector = malloc(sizeof(void*));
600 | return vector;
601 | }
602 | }
603 |
604 | err:
605 | while ((*argc)--)
606 | sdsfree(vector[*argc]);
607 | free(vector);
608 | if (current) sdsfree(current);
609 | *argc = 0;
610 | return NULL;
611 | }
612 |
613 | /* Modify the string substituting all the occurrences of the set of
614 | * characters specified in the 'from' string to the corresponding character
615 | * in the 'to' array.
616 | *
617 | * For instance: sdsmapchars(mystring, "ho", "01", 2)
618 | * will have the effect of turning the string "hello" into "0ell1".
619 | *
620 | * The function returns the sds string pointer, that is always the same
621 | * as the input pointer since no resize is needed. */
622 | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
623 | size_t j, i, l = sdslen(s);
624 |
625 | for (j = 0; j < l; j++) {
626 | for (i = 0; i < setlen; i++) {
627 | if (s[j] == from[i]) {
628 | s[j] = to[i];
629 | break;
630 | }
631 | }
632 | }
633 | return s;
634 | }
--------------------------------------------------------------------------------
/STHTMLPP/sds.h:
--------------------------------------------------------------------------------
1 | /* SDSLib, A C dynamic strings library
2 | *
3 | * Copyright (c) 2006-2010, Salvatore Sanfilippo
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | #ifndef __SDS_H
32 | #define __SDS_H
33 |
34 | #define SDS_MAX_PREALLOC (1024*1024)
35 |
36 | #include
37 | #include
38 |
39 | typedef char *sds;
40 |
41 | typedef struct sdshdr {
42 | int len;
43 | int free;
44 | char buf[];
45 | }sdshdr;
46 |
47 | static inline size_t sdslen(const sds s) {
48 | struct sdshdr *sh = (sdshdr*)(s - (sizeof(struct sdshdr)));
49 | return sh->len;
50 | }
51 |
52 | static inline size_t sdsavail(const sds s) {
53 | struct sdshdr *sh = (sdshdr*)(s - (sizeof(struct sdshdr)));
54 | return sh->free;
55 | }
56 |
57 | sds sdsnewlen(const void *init, size_t initlen);
58 | sds sdsnew(const char *init);
59 | sds sdsempty();
60 | size_t sdslen(const sds s);
61 | sds sdsdup(const sds s);
62 | void sdsfree(sds s);
63 | size_t sdsavail(const sds s);
64 | sds sdsgrowzero(sds s, size_t len);
65 | sds sdscatlen(sds s, const void *t, size_t len);
66 | sds sdscat(sds s, const char *t);
67 | sds sdscatsds(sds s, const sds t);
68 | sds sdscpylen(sds s, const char *t, size_t len);
69 | sds sdscpy(sds s, const char *t);
70 |
71 | sds sdscatvprintf(sds s, const char *fmt, va_list ap);
72 | #ifdef __GNUC__
73 | sds sdscatprintf(sds s, const char *fmt, ...)
74 | __attribute__((format(printf, 2, 3)));
75 | #else
76 | sds sdscatprintf(sds s, const char *fmt, ...);
77 | #endif
78 |
79 | sds sdstrim(sds s, const char *cset);
80 | sds sdsrange(sds s, int start, int end);
81 | void sdsupdatelen(sds s);
82 | void sdsclear(sds s);
83 | int sdscmp(const sds s1, const sds s2);
84 | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
85 | void sdsfreesplitres(sds *tokens, int count);
86 | void sdstolower(sds s);
87 | void sdstoupper(sds s);
88 | sds sdsfromlonglong(long long value);
89 | sds sdscatrepr(sds s, const char *p, size_t len);
90 | sds *sdssplitargs(const char *line, int *argc);
91 | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
92 |
93 | /* Low level functions exposed to the user API */
94 | sds sdsMakeRoomFor(sds s, size_t addlen);
95 | void sdsIncrLen(sds s, int incr);
96 | sds sdsRemoveFreeSpace(sds s);
97 | size_t sdsAllocSize(sds s);
98 |
99 | #endif
--------------------------------------------------------------------------------
/STHTMLPP/stdafx.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/STHTMLPP/stdafx.cpp
--------------------------------------------------------------------------------
/STHTMLPP/stdafx.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/STHTMLPP/stdafx.h
--------------------------------------------------------------------------------
/STHTMLPP/strings.h:
--------------------------------------------------------------------------------
1 | /*Dummy file to satisfy source file dependencies on Windows platform*/
2 | #define strcasecmp _stricmp
3 | #define strncasecmp _strnicmp
4 | #define inline __inline
5 |
--------------------------------------------------------------------------------
/STHTMLPP/targetver.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/STHTMLPP/targetver.h
--------------------------------------------------------------------------------
/STHTMLPP/utf8_strings.cpp:
--------------------------------------------------------------------------------
1 | #include "utf8_strings.h"
2 |
3 |
4 | litehtml::utf8_to_wchar::utf8_to_wchar(const char* val)
5 | {
6 | m_utf8 = (const byte*)val;
7 | while (true)
8 | {
9 | ucode_t wch = get_char();
10 | if (!wch) break;
11 | m_str += wch;
12 | }
13 | }
14 |
15 | ucode_t litehtml::utf8_to_wchar::get_char()
16 | {
17 | ucode_t b1 = getb();
18 |
19 | if (!b1)
20 | {
21 | return 0;
22 | }
23 |
24 | // Determine whether we are dealing
25 | // with a one-, two-, three-, or four-
26 | // byte sequence.
27 | if ((b1 & 0x80) == 0)
28 | {
29 | // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx
30 | return b1;
31 | }
32 | else if ((b1 & 0xe0) == 0xc0)
33 | {
34 | // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
35 | ucode_t r = (b1 & 0x1f) << 6;
36 | r |= get_next_utf8(getb());
37 | return r;
38 | }
39 | else if ((b1 & 0xf0) == 0xe0)
40 | {
41 | // 3-byte sequence: zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
42 | ucode_t r = (b1 & 0x0f) << 12;
43 | r |= get_next_utf8(getb()) << 6;
44 | r |= get_next_utf8(getb());
45 | return r;
46 | }
47 | else if ((b1 & 0xf8) == 0xf0)
48 | {
49 | // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx
50 | // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
51 | // (uuuuu = wwww + 1)
52 | int b2 = get_next_utf8(getb());
53 | int b3 = get_next_utf8(getb());
54 | int b4 = get_next_utf8(getb());
55 | return ((b1 & 7) << 18) | ((b2 & 0x3f) << 12) |
56 | ((b3 & 0x3f) << 6) | (b4 & 0x3f);
57 | }
58 |
59 | //bad start for UTF-8 multi-byte sequence
60 | return '?';
61 | }
62 |
63 | litehtml::wchar_to_utf8::wchar_to_utf8(const wchar_t* val)
64 | {
65 | unsigned int code;
66 | for (int i = 0; val[i]; i++)
67 | {
68 | code = val[i];
69 | if (code <= 0x7F)
70 | {
71 | m_str += (char)code;
72 | }
73 | else if (code <= 0x7FF)
74 | {
75 | m_str += (code >> 6) + 192;
76 | m_str += (code & 63) + 128;
77 | }
78 | else if (0xd800 <= code && code <= 0xdfff)
79 | {
80 | //invalid block of utf8
81 | }
82 | else if (code <= 0xFFFF)
83 | {
84 | m_str += (code >> 12) + 224;
85 | m_str += ((code >> 6) & 63) + 128;
86 | m_str += (code & 63) + 128;
87 | }
88 | else if (code <= 0x10FFFF)
89 | {
90 | m_str += (code >> 18) + 240;
91 | m_str += ((code >> 12) & 63) + 128;
92 | m_str += ((code >> 6) & 63) + 128;
93 | m_str += (code & 63) + 128;
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/STHTMLPP/utf8_strings.h:
--------------------------------------------------------------------------------
1 | #ifndef LH_UTF8_STRINGS_H
2 | #define LH_UTF8_STRINGS_H
3 |
4 | typedef unsigned char byte;
5 | typedef unsigned int ucode_t;
6 | typedef wchar_t tchar_t;
7 | #include
8 |
9 | using namespace std;
10 | namespace litehtml
11 | {
12 | class utf8_to_wchar
13 | {
14 | const byte* m_utf8;
15 | std::wstring m_str;
16 | public:
17 | utf8_to_wchar(const char* val);
18 | operator const wchar_t*() const
19 | {
20 | return m_str.c_str();
21 | }
22 | private:
23 | ucode_t getb()
24 | {
25 | if (!(*m_utf8)) return 0;
26 | return *m_utf8++;
27 | }
28 | ucode_t get_next_utf8(ucode_t val)
29 | {
30 | return (val & 0x3f);
31 | }
32 | ucode_t get_char();
33 | };
34 |
35 | class wchar_to_utf8
36 | {
37 | std::string m_str;
38 | public:
39 | wchar_to_utf8(const wchar_t* val);
40 | operator const char*() const
41 | {
42 | return m_str.c_str();
43 | }
44 | };
45 |
46 | #ifdef LITEHTML_UTF8
47 | #define litehtml_from_utf8(str) str
48 | #define litehtml_to_utf8(str) str
49 | #define litehtml_from_wchar(str) wchar_to_utf8(str)
50 | #else
51 | #define litehtml_from_utf8(str) utf8_to_wchar(str)
52 | #define litehtml_from_wchar(str) str
53 | #define litehtml_to_utf8(str) wchar_to_utf8(str)
54 | #endif
55 | }
56 |
57 | #endif // LH_UTF8_STRINGS_H
--------------------------------------------------------------------------------
/img/123.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/img/123.PNG
--------------------------------------------------------------------------------
/img/456.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1694439208/gumbo-Elss/abd193029bf2747f9882889dd115b5e759911ac2/img/456.PNG
--------------------------------------------------------------------------------