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, unsigned int* cnt, int* dc)
114 : {
115 : char name[MAX_TAG_NAME_LEN];
116 4587 : GetTagName(t, name, sizeof(name));
117 4587 : if (name[0] == '\0') {
118 1 : return tagEnd + 1;
119 : }
120 :
121 4586 : bool selfClose = IsSelfClose(t, tagEnd);
122 4586 : if (*cnt < maxTags) {
123 4586 : TagEntry* e = &tags[*cnt];
124 4586 : (void)memset_s(e, sizeof(*e), 0, sizeof(*e));
125 4586 : if (strcpy_s(e->tagName, sizeof(e->tagName), name) != 0) {
126 0 : TOPO_ERR("HandleOpenTag: strcpy_s failed, name=%s", name);
127 0 : return NULL;
128 : }
129 4586 : e->isSelfClose = selfClose;
130 4586 : e->depth = *dc;
131 4586 : ExtractAttrs(t, e);
132 4586 : (*cnt)++;
133 : }
134 :
135 4586 : if (!selfClose) {
136 2021 : (*dc)++;
137 : }
138 4586 : return tagEnd + 1;
139 : }
140 :
141 : /* ─── 逐行解析 XML,识别标签 ─── */
142 : /* 逐行解析 XML,识别标签 */
143 384 : static TopoAddrResult ParseXmlLines(FILE* fp, TagEntry* tags, unsigned int maxTags, unsigned int* cnt)
144 : {
145 384 : int dc = 0;
146 : char line[MAX_LINE_LEN];
147 6354 : while (fgets(line, sizeof(line), fp) != NULL) {
148 5970 : char* t = line;
149 12580 : while (*t != '\0') {
150 18780 : while (*t != '\0' && isspace((unsigned char)*t)) {
151 6200 : t++;
152 : }
153 12580 : if (*t == '\0' || strncmp(t, "<!--", 4) == 0) {
154 : break;
155 : }
156 :
157 6611 : char* tagEnd = strchr(t, '>');
158 6611 : if (tagEnd == NULL) {
159 1 : break;
160 : }
161 :
162 6610 : if (t[0] == '<' && t[1] == '/') {
163 2023 : if (dc > 0) {
164 2021 : dc--;
165 : }
166 2023 : t = tagEnd + 1;
167 2023 : continue;
168 : }
169 :
170 4587 : if (t[0] == '<') {
171 4587 : t = HandleOpenTag(t, tagEnd, tags, maxTags, cnt, &dc);
172 4587 : if (t == NULL) {
173 0 : return TOPO_ERR_INTERNAL;
174 : }
175 4587 : continue;
176 : }
177 0 : break;
178 : }
179 : }
180 384 : return TOPO_SUCCESS;
181 : }
182 :
183 : /* ─── 核心解析函数 ─── */
184 :
185 396 : TopoAddrResult ParseXmlTags(const char* xmlPath, TagEntry* tags, unsigned int* tagCount, unsigned int maxTags)
186 : {
187 396 : *tagCount = 0;
188 :
189 396 : FILE* fp = fopen(xmlPath, "rb");
190 396 : if (fp == NULL) {
191 11 : TOPO_INFO("ParseXmlTags: cannot open %s", xmlPath);
192 11 : return TOPO_ERR_OPEN_FILE;
193 : }
194 :
195 : struct stat st;
196 385 : if (fstat(fileno(fp), &st) != 0 || st.st_size == 0) {
197 1 : TOPO_ERR("ParseXmlTags: stat failed or empty file, path=%s", xmlPath);
198 1 : fclose(fp);
199 1 : return TOPO_ERR_OPEN_FILE;
200 : }
201 :
202 384 : unsigned int cnt = 0;
203 384 : if (ParseXmlLines(fp, tags, maxTags, &cnt) != TOPO_SUCCESS) {
204 0 : fclose(fp);
205 0 : return TOPO_ERR_INTERNAL;
206 : }
207 :
208 384 : fclose(fp);
209 384 : *tagCount = cnt;
210 384 : if (cnt == 0) {
211 0 : TOPO_ERR("ParseXmlTags: no valid tags found in %s", xmlPath);
212 0 : return TOPO_ERR_NOT_FOUND;
213 : }
214 384 : return TOPO_SUCCESS;
215 : }
|