Moving in e2sim originally from it/test/simulators
[sim/e2-interface.git] / e2sim / ASN1c / xer_support.c
1 /*****************************************************************************
2 #                                                                            *
3 # Copyright 2019 AT&T Intellectual Property                                  *
4 #                                                                            *
5 # Licensed under the Apache License, Version 2.0 (the "License");            *
6 # you may not use this file except in compliance with the License.           *
7 # You may obtain a copy of the License at                                    *
8 #                                                                            *
9 #      http://www.apache.org/licenses/LICENSE-2.0                            *
10 #                                                                            *
11 # Unless required by applicable law or agreed to in writing, software        *
12 # distributed under the License is distributed on an "AS IS" BASIS,          *
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
14 # See the License for the specific language governing permissions and        *
15 # limitations under the License.                                             *
16 #                                                                            *
17 ******************************************************************************/
18
19 /*
20  * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com.
21  * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>.
22  *      All rights reserved.
23  * Redistribution and modifications are permitted subject to BSD license.
24  */
25 #include <asn_system.h>
26 #include <xer_support.h>
27
28 /* Parser states */
29 typedef enum {
30         ST_TEXT,
31         ST_TAG_START,
32         ST_TAG_BODY,
33         ST_TAG_QUOTE_WAIT,
34         ST_TAG_QUOTED_STRING,
35         ST_TAG_UNQUOTED_STRING,
36         ST_COMMENT_WAIT_DASH1,  /* "<!--"[1] */
37         ST_COMMENT_WAIT_DASH2,  /* "<!--"[2] */
38         ST_COMMENT,
39         ST_COMMENT_CLO_DASH2,   /* "-->"[0] */
40         ST_COMMENT_CLO_RT       /* "-->"[1] */
41 } pstate_e;
42
43 static const int
44 _charclass[256] = {
45         0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0,
46         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
47         1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
48         2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0,       /* 01234567 89       */
49         0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,       /*  ABCDEFG HIJKLMNO */
50         3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0,       /* PQRSTUVW XYZ      */
51         0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,       /*  abcdefg hijklmno */
52         3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0        /* pqrstuvw xyz      */
53 };
54 #define WHITESPACE(c)   (_charclass[(unsigned char)(c)] == 1)
55 #define ALNUM(c)        (_charclass[(unsigned char)(c)] >= 2)
56 #define ALPHA(c)        (_charclass[(unsigned char)(c)] == 3)
57
58 /* Aliases for characters, ASCII/UTF-8 */
59 #define EXCLAM  0x21    /* '!' */
60 #define CQUOTE  0x22    /* '"' */
61 #define CDASH   0x2d    /* '-' */
62 #define CSLASH  0x2f    /* '/' */
63 #define LANGLE  0x3c    /* '<' */
64 #define CEQUAL  0x3d    /* '=' */
65 #define RANGLE  0x3e    /* '>' */
66 #define CQUEST  0x3f    /* '?' */
67
68 /* Invoke token callback */
69 #define TOKEN_CB_CALL(type, _ns, _current_too, _final) do {     \
70                 int _ret;                                       \
71                 pstate_e ns  = _ns;                             \
72                 ssize_t _sz = (p - chunk_start) + _current_too; \
73                 if (!_sz) {                                     \
74                         /* Shortcut */                          \
75                         state = _ns;                            \
76                         break;                                  \
77                 }                                               \
78                 _ret = cb(type, chunk_start, _sz, key);         \
79                 if(_ret < _sz) {                                \
80                         if(_current_too && _ret == -1)          \
81                                 state = ns;                     \
82                         goto finish;                            \
83                 }                                               \
84                 chunk_start = p + _current_too;                 \
85                 state = ns;                                     \
86         } while(0)
87
88 #define TOKEN_CB(_type, _ns, _current_too)                      \
89         TOKEN_CB_CALL(_type, _ns, _current_too, 0)
90
91 #define PXML_TAG_FINAL_CHUNK_TYPE      PXML_TAG_END
92 #define PXML_COMMENT_FINAL_CHUNK_TYPE  PXML_COMMENT_END
93
94 #define TOKEN_CB_FINAL(_type, _ns, _current_too)                \
95         TOKEN_CB_CALL( _type ## _FINAL_CHUNK_TYPE , _ns, _current_too, 1)
96
97 /*
98  * Parser itself
99  */
100 ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) {
101         pstate_e state = (pstate_e)*stateContext;
102         const char *chunk_start = (const char *)xmlbuf;
103         const char *p = chunk_start;
104         const char *end = p + size;
105
106         for(; p < end; p++) {
107           int C = *(const unsigned char *)p;
108           switch(state) {
109           case ST_TEXT:
110                 /*
111                  * Initial state: we're in the middle of some text,
112                  * or just have started.
113                  */
114                 if (C == LANGLE) 
115                         /* We're now in the tag, probably */
116                         TOKEN_CB(PXML_TEXT, ST_TAG_START, 0);
117                 break;
118           case ST_TAG_START:
119                 if (ALPHA(C) || (C == CSLASH))
120                         state = ST_TAG_BODY;
121                 else if (C == EXCLAM)
122                         state = ST_COMMENT_WAIT_DASH1;
123                 else 
124                         /*
125                          * Not characters and not whitespace.
126                          * Must be something like "3 < 4".
127                          */
128                         TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */
129                 break;
130           case ST_TAG_BODY:
131                 switch(C) {
132                 case RANGLE:
133                         /* End of the tag */
134                         TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
135                         break;
136                 case LANGLE:
137                         /*
138                          * The previous tag wasn't completed, but still
139                          * recognized as valid. (Mozilla-compatible)
140                          */
141                         TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0);      
142                         break;
143                 case CEQUAL:
144                         state = ST_TAG_QUOTE_WAIT;
145                         break;
146                 }
147                 break;
148           case ST_TAG_QUOTE_WAIT:
149                 /*
150                  * State after the equal sign ("=") in the tag.
151                  */
152                 switch(C) {
153                 case CQUOTE:
154                         state = ST_TAG_QUOTED_STRING;
155                         break;
156                 case RANGLE:
157                         /* End of the tag */
158                         TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
159                         break;
160                 default:
161                         if(!WHITESPACE(C))
162                                 /* Unquoted string value */
163                                 state = ST_TAG_UNQUOTED_STRING;
164                 }
165                 break;
166           case ST_TAG_QUOTED_STRING:
167                 /*
168                  * Tag attribute's string value in quotes.
169                  */
170                 if(C == CQUOTE) {
171                         /* Return back to the tag state */
172                         state = ST_TAG_BODY;
173                 }
174                 break;
175           case ST_TAG_UNQUOTED_STRING:
176                 if(C == RANGLE) {
177                         /* End of the tag */
178                         TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1);
179                 } else if(WHITESPACE(C)) {
180                         /* Return back to the tag state */
181                         state = ST_TAG_BODY;
182                 }
183                 break;
184           case ST_COMMENT_WAIT_DASH1:
185                 if(C == CDASH) {
186                         state = ST_COMMENT_WAIT_DASH2;
187                 } else {
188                         /* Some ordinary tag. */
189                         state = ST_TAG_BODY;
190                 }
191                 break;
192           case ST_COMMENT_WAIT_DASH2:
193                 if(C == CDASH) {
194                         /* Seen "<--" */
195                         state = ST_COMMENT;
196                 } else {
197                         /* Some ordinary tag */
198                         state = ST_TAG_BODY;
199                 }
200                 break;
201           case ST_COMMENT:
202                 if(C == CDASH) {
203                         state = ST_COMMENT_CLO_DASH2;
204                 }
205                 break;
206           case ST_COMMENT_CLO_DASH2:
207                 if(C == CDASH) {
208                         state = ST_COMMENT_CLO_RT;
209                 } else {
210                         /* This is not an end of a comment */
211                         state = ST_COMMENT;
212                 }
213                 break;
214           case ST_COMMENT_CLO_RT:
215                 if(C == RANGLE) {
216                         TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1);
217                 } else if(C == CDASH) {
218                         /* Maintain current state, still waiting for '>' */
219                 } else {
220                         state = ST_COMMENT;
221                 }
222                 break;
223           } /* switch(*ptr) */
224         } /* for() */
225
226         /*
227          * Flush the partially processed chunk, state permitting.
228          */
229         if(p - chunk_start) {
230                 switch (state) {
231                 case ST_COMMENT:
232                         TOKEN_CB(PXML_COMMENT, state, 0);
233                         break;
234                 case ST_TEXT:
235                         TOKEN_CB(PXML_TEXT, state, 0);
236                         break;
237                 default: break; /* a no-op */
238                 }
239         }
240
241 finish:
242         *stateContext = (int)state;
243         return chunk_start - (const char *)xmlbuf;
244 }
245