Line data Source code
1 : /**
2 : * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "xml_parser.h"
12 :
13 : #include <ctype.h>
14 : #include <stdio.h>
15 : #include <string.h>
16 : #include <sys/stat.h>
17 :
18 : #include "securec.h"
19 : #include "topo_addr_info_log.h"
20 :
21 : #define MAX_LINE_LEN 4096
22 :
23 : /* ─── 工具函数 ─── */
24 :
25 2805 : const char *TagFindAttr(const TagEntry *e, const char *name)
26 : {
27 2805 : for (int i = 0; i < e->attrCount; i++) {
28 2803 : if (strcmp(e->attrs[i].name, name) == 0) {
29 2803 : return e->attrs[i].value;
30 : }
31 : }
32 2 : return NULL;
33 : }
34 :
35 4586 : static bool IsSelfClose(const char *tag, const char *tagEnd)
36 : {
37 4586 : size_t n = (size_t)(tagEnd - tag + 1);
38 4586 : return n >= 2 && tag[n - 2] == '/';
39 : }
40 :
41 4587 : static void GetTagName(const char *tag, char *name, size_t len)
42 : {
43 4587 : if (name == NULL || len == 0) {
44 0 : return;
45 : }
46 :
47 4587 : const char *p = tag + 1;
48 4587 : if (*p == '/') {
49 0 : p++;
50 : }
51 4587 : const char *start = p;
52 19066 : while (*p != '\0' && *p != ' ' && *p != '>' && *p != '/') {
53 14479 : p++;
54 : }
55 4587 : size_t n = (size_t)(p - start);
56 4587 : if (n >= len) {
57 0 : n = len - 1;
58 : }
59 4587 : if (strncpy_s(name, len, start, n) != 0) {
60 0 : name[0] = '\0';
61 0 : return;
62 : }
63 4587 : name[n] = '\0';
64 : }
65 :
66 4586 : static void ExtractAttrs(const char *tag, TagEntry *e)
67 : {
68 4586 : int ac = e->attrCount;
69 4586 : const char *scan = tag;
70 :
71 8568 : while (ac < MAX_ATTRS_PER_TAG) {
72 8568 : scan = strchr(scan, ' ');
73 8568 : if (scan == NULL) {
74 4200 : break;
75 : }
76 4368 : scan++;
77 4368 : if (*scan == '\0') {
78 0 : break;
79 : }
80 4368 : const char *eq = strchr(scan, '=');
81 4368 : if (eq == NULL || eq <= scan) {
82 : break;
83 : }
84 3983 : size_t nlen = (size_t)(eq - scan);
85 3983 : if (nlen >= MAX_ATTR_NAME_LEN) {
86 0 : nlen = MAX_ATTR_NAME_LEN - 1;
87 : }
88 3983 : (void)strncpy_s(e->attrs[ac].name, sizeof(e->attrs[ac].name), scan, nlen);
89 :
90 3983 : const char *vq = strchr(eq, '\"');
91 3983 : if (vq == NULL) {
92 1 : break;
93 : }
94 3982 : vq++;
95 3982 : const char *ve = strchr(vq, '\"');
96 3982 : if (ve == NULL) {
97 0 : break;
98 : }
99 3982 : size_t vlen = (size_t)(ve - vq);
100 3982 : if (vlen >= MAX_ATTR_VAL_LEN) {
101 0 : vlen = MAX_ATTR_VAL_LEN - 1;
102 : }
103 3982 : (void)strncpy_s(e->attrs[ac].value, sizeof(e->attrs[ac].value), vq, vlen);
104 :
105 3982 : ac++;
106 3982 : scan = ve + 1;
107 : }
108 4586 : e->attrCount = ac;
109 4586 : }
110 :
111 : /* ─── 内部辅助:处理一个开标签 ─── */
112 : /* 返回 tagEnd+1(下一位置),通过指针更新 cnt / dc */
113 4587 : static char *HandleOpenTag(char *t, char *tagEnd, TagEntry *tags, unsigned int maxTags,
114 : unsigned int *cnt, int *dc)
115 : {
116 : char name[MAX_TAG_NAME_LEN];
117 4587 : GetTagName(t, name, sizeof(name));
118 4587 : if (name[0] == '\0') {
119 1 : return tagEnd + 1;
120 : }
121 :
122 4586 : bool selfClose = IsSelfClose(t, tagEnd);
123 4586 : if (*cnt < maxTags) {
124 4586 : TagEntry *e = &tags[*cnt];
125 4586 : (void)memset_s(e, sizeof(*e), 0, sizeof(*e));
126 4586 : if (strcpy_s(e->tagName, sizeof(e->tagName), name) != 0) {
127 0 : TOPO_ERR("HandleOpenTag: strcpy_s failed, name=%s", name);
128 0 : return NULL;
129 : }
130 4586 : e->isSelfClose = selfClose;
131 4586 : e->depth = *dc;
132 4586 : ExtractAttrs(t, e);
133 4586 : (*cnt)++;
134 : }
135 :
136 4586 : if (!selfClose) {
137 2021 : (*dc)++;
138 : }
139 4586 : return tagEnd + 1;
140 : }
141 :
142 : /* ─── 逐行解析 XML,识别标签 ─── */
143 : /* 逐行解析 XML,识别标签 */
144 384 : static TopoAddrResult ParseXmlLines(FILE *fp, TagEntry *tags, unsigned int maxTags,
145 : unsigned int *cnt)
146 : {
147 384 : int dc = 0;
148 : char line[MAX_LINE_LEN];
149 6354 : while (fgets(line, sizeof(line), fp) != NULL) {
150 5970 : char *t = line;
151 12580 : while (*t != '\0') {
152 18780 : while (*t != '\0' && isspace((unsigned char)*t)) {
153 6200 : t++;
154 : }
155 12580 : if (*t == '\0' || strncmp(t, "<!--", 4) == 0) {
156 : break;
157 : }
158 :
159 6611 : char *tagEnd = strchr(t, '>');
160 6611 : if (tagEnd == NULL) {
161 1 : break;
162 : }
163 :
164 6610 : if (t[0] == '<' && t[1] == '/') {
165 2023 : if (dc > 0) {
166 2021 : dc--;
167 : }
168 2023 : t = tagEnd + 1;
169 2023 : continue;
170 : }
171 :
172 4587 : if (t[0] == '<') {
173 4587 : t = HandleOpenTag(t, tagEnd, tags, maxTags, cnt, &dc);
174 4587 : if (t == NULL) {
175 0 : return TOPO_ERR_INTERNAL;
176 : }
177 4587 : continue;
178 : }
179 0 : break;
180 : }
181 : }
182 384 : return TOPO_SUCCESS;
183 : }
184 :
185 : /* ─── 核心解析函数 ─── */
186 :
187 396 : TopoAddrResult ParseXmlTags(const char *xmlPath, TagEntry *tags, unsigned int *tagCount, unsigned int maxTags)
188 : {
189 396 : *tagCount = 0;
190 :
191 396 : FILE *fp = fopen(xmlPath, "rb");
192 396 : if (fp == NULL) {
193 11 : TOPO_ERR("ParseXmlTags: cannot open %s", xmlPath);
194 11 : return TOPO_ERR_OPEN_FILE;
195 : }
196 :
197 : struct stat st;
198 385 : if (fstat(fileno(fp), &st) != 0 || st.st_size == 0) {
199 1 : TOPO_ERR("ParseXmlTags: stat failed or empty file, path=%s", xmlPath);
200 1 : fclose(fp);
201 1 : return TOPO_ERR_OPEN_FILE;
202 : }
203 :
204 384 : unsigned int cnt = 0;
205 384 : if (ParseXmlLines(fp, tags, maxTags, &cnt) != TOPO_SUCCESS) {
206 0 : fclose(fp);
207 0 : return TOPO_ERR_INTERNAL;
208 : }
209 :
210 384 : fclose(fp);
211 384 : *tagCount = cnt;
212 384 : if (cnt == 0) {
213 0 : TOPO_ERR("ParseXmlTags: no valid tags found in %s", xmlPath);
214 0 : return TOPO_ERR_NOT_FOUND;
215 : }
216 384 : return TOPO_SUCCESS;
217 : }
|