1 #include "wwwsys.h"
2 /*#include "HTUtils.h" */
3 #include "HTList.h"
4 #include "HTString.h"
5 #include "CSParse.h"
6 #include "CSLL.h"
7 #include "CSLLSt.h"
8 
9 #define GetCSLabel(A) ((A)->target.pCSLabel)
10 #define SETNEXTSTATE(target, subState) \
11   pCSParse->pTargetObject = target; \
12   pCSParse->currentSubState = subState;
13 
14 
15 /* C H A R A C T E R   S E T   V A L I D A T I O N */
16 /* The BNF for PICS labels describes the valid character ranges for each of
17  * the label fields. Defining NO_CHAR_TEST will disable the tedious checking
18  * of these ranges for a slight performance increase.
19  */
20 #ifdef NO_CHAR_TEST
21 #define charSetOK(A, B, C)
22 #define CHECK_CAR_SET(A)
23 #define SET_CHAR_SET(A)
24 #else /* !NO_CHAR_TEST */
25 typedef enum {CharSet_ALPHAS = 1, CharSet_DIGITS = 2, CharSet_PLUSMINUS = 4, CharSet_FORSLASH = 8,
26               CharSet_EXTENS = 0x10, CharSet_BASE64_EXTRAS = 0x20, CharSet_DATE_EXTRAS = 0x40, CharSet_URL_EXTRAS = 0x80,
27               /* ------------------ BNF names are combinations of the above ------------------- */
28               CharSet_NUMBER        = CharSet_DIGITS | CharSet_PLUSMINUS,
29               CharSet_ALPHANUMPM    = CharSet_ALPHAS | CharSet_DIGITS | CharSet_PLUSMINUS,
30               CharSet_TRANSMIT_NAME = CharSet_ALPHANUMPM | CharSet_FORSLASH,
31               CharSet_EXT_ALPHANUM  = CharSet_ALPHANUMPM | CharSet_EXTENS,
32               CharSet_BASE64        = CharSet_ALPHAS | CharSet_DIGITS | CharSet_BASE64_EXTRAS,
33               CharSet_URL           = CharSet_ALPHAS | CharSet_DIGITS | CharSet_URL_EXTRAS,
34               CharSet_DATE          = CharSet_DIGITS | CharSet_DATE_EXTRAS,
35               CharSet_EXT_DATA      = CharSet_DATE | CharSet_URL | CharSet_NUMBER | CharSet_EXT_ALPHANUM
36              } CharSet_t;
37 
38 PRIVATE BOOL charSetOK(CSParse_t * pCSParse, char * checkMe, CharSet_t set);
39 #define CHECK_CAR_SET(A) \
40     if (!charSetOK(pCSParse, token, A)) \
41         return StateRet_ERROR_BAD_CHAR;
42 #define SET_CHAR_SET(A) pCSLabel->targetCharSet = A;
43 #endif /* !NO_CHAR_TEST */
44 
45 /* C S L L S t a t e */
46 /* This holds label list data and the methods to view it. All application
47  * interface is intended to go through these methods. See User/Parsing.html
48  */
49 struct CSLabel_s {
50     CSLLData_t * pCSLLData;
51 
52     LabelError_t * pCurrentLabelError;
53     LabelOptions_t * pCurrentLabelOptions;
54 	Extension_t * pCurrentExtension;
55 	ExtensionData_t * pCurrentExtensionData;
56 
57     ServiceInfo_t * pCurrentServiceInfo;
58     Label_t * pCurrentLabel;
59     int currentLabelNumber;
60     HTList * pCurrentLabelTree;
61     SingleLabel_t * pCurrentSingleLabel;
62     LabelRating_t * pCurrentLabelRating;
63     Range_t * pCurrentRange;
64 #ifndef NO_CHAR_TEST
65     CharSet_t targetCharSet;
66 #endif
67 
68 	LabelTargetCallback_t * pLabelTargetCallback;
69 	LLErrorHandler_t * pLLErrorHandler;
70 };
71 
72 /* forward references to parser functions */
73 PRIVATE TargetObject_t LabelList_targetObject;
74 PRIVATE TargetObject_t ServiceInfo_targetObject;
75 PRIVATE TargetObject_t ServiceNoRat_targetObject;
76 PRIVATE TargetObject_t ServiceError_targetObject;
77 PRIVATE TargetObject_t Label_targetObject;
78 PRIVATE TargetObject_t LabelError_targetObject;
79 PRIVATE TargetObject_t LabelTree_targetObject;
80 PRIVATE TargetObject_t SingleLabel_targetObject;
81 PRIVATE TargetObject_t LabelRating_targetObject;
82 PRIVATE TargetObject_t LabelRatingRange_targetObject;
83 PRIVATE TargetObject_t Extension_targetObject;
84 PRIVATE TargetObject_t ExtensionData_targetObject;
85 PRIVATE TargetObject_t Awkward_targetObject;
86 PRIVATE Check_t hasToken;
87 PRIVATE Check_t LabelList_getVersion;
88 PRIVATE Check_t ServiceInfo_getServiceId;
89 PRIVATE Check_t error_getExpl;
90 PRIVATE Check_t getOption;
91 PRIVATE Check_t getOptionValue;
92 PRIVATE Check_t LabelRating_getId;
93 PRIVATE Check_t LabelRating_getValue;
94 PRIVATE Check_t LabelRatingRange_get;
95 PRIVATE Check_t isQuoted;
96 PRIVATE Check_t Extension_getURL;
97 PRIVATE Check_t ExtensionData_getData;
98 PRIVATE Open_t LabelList_open;
99 PRIVATE Open_t ServiceInfo_open;
100 PRIVATE Open_t error_open;
101 PRIVATE Open_t Label_open;
102 PRIVATE Open_t LabelTree_open;
103 PRIVATE Open_t SingleLabel_open;
104 PRIVATE Open_t LabelRating_open;
105 PRIVATE Open_t LabelRatingRange_open;
106 PRIVATE Open_t Awkward_open;
107 PRIVATE Open_t Extension_open;
108 PRIVATE Open_t ExtensionData_open;
109 PRIVATE Close_t LabelList_close;
110 PRIVATE Close_t ServiceInfo_close;
111 PRIVATE Close_t error_close;
112 PRIVATE Close_t Label_close;
113 PRIVATE Close_t LabelTree_close;
114 PRIVATE Close_t SingleLabel_close;
115 PRIVATE Close_t LabelRating_close;
116 PRIVATE Close_t LabelRatingRange_close;
117 PRIVATE Close_t Awkward_close;
118 PRIVATE Close_t Extension_close;
119 PRIVATE Close_t ExtensionData_close;
120 PRIVATE Destroy_t LabelList_destroy;
121 PRIVATE Destroy_t ServiceInfo_destroy;
122 PRIVATE Destroy_t Label_destroy;
123 PRIVATE Destroy_t LabelTree_destroy;
124 PRIVATE Destroy_t SingleLabel_destroy;
125 PRIVATE Destroy_t LabelRating_destroy;
126 PRIVATE Destroy_t LabelRatingRange_destroy;
127 PRIVATE Destroy_t Awkward_destroy;
128 PRIVATE Destroy_t error_destroy;
129 PRIVATE Destroy_t Extension_destroy;
130 PRIVATE Destroy_t ExtensionData_destroy;
131 PRIVATE Prep_t ServiceInfo_clearOpts;
132 PRIVATE Prep_t LabelRating_next;
133 PRIVATE Prep_t Extension_mandatory;
134 PRIVATE Prep_t Extension_next;
135 PRIVATE Prep_t ExtensionData_next;
136 PRIVATE Prep_t SingleLabel_doClose;
137 PRIVATE Prep_t Label_doClose;
138 
139 PRIVATE TargetChangeCallback_t targetChangeCallback;
140 PRIVATE ParseErrorHandler_t parseErrorHandler;
141 
142 /* CSParse_doc states */
143 /* L A B E L   L I S T   P A R S E R   S T A T E S */
144 /* This contains all the states in the BNF for PICS labels.
145  * See User/Parsing.html for details.
146  */
147 PRIVATE StateToken_t LabelList_stateTokens[] = {
148     /* A: fresh LabelList
149        C: expect end */
150      {       "open", SubState_N,    Punct_ALL,              0,        0, 0, 0,   &LabelList_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
151      {"get version", SubState_A,  Punct_WHITE, &LabelList_getVersion, 0, 0, 0, &ServiceInfo_targetObject, SubState_N, 0, 0},
152      {"end of list", SubState_C, Punct_RPAREN,              0,        0, 0, 0,   &LabelList_targetObject, SubState_A, Command_MATCHANY|Command_CLOSE, 0}
153     };
154 PRIVATE TargetObject_t LabelList_targetObject = {"LabelList", &LabelList_open, &LabelList_close, &LabelList_destroy, LabelList_stateTokens, raysize(LabelList_stateTokens), CSLLTC_LIST};
155 
156 PRIVATE StateToken_t ServiceInfo_stateTokens[] = {
157     /* A: fresh ServiceInfo
158        B: has service id
159        C: needs option value
160        D: call from Awkward or NoRat to close
161        E: call from Awkward to re-enter
162        F: call from Awkward to handle no-ratings error */
163      {             "open", SubState_N,    Punct_ALL,                0,        0,   0, 0, &ServiceInfo_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
164      {     "error w/o id", SubState_A, Punct_LPAREN,                0, "error",    0, 0, &ServiceNoRat_targetObject, SubState_N, 0, 0},
165      {       "service id", SubState_A,  Punct_WHITE, &ServiceInfo_getServiceId, 0, 0, 0,  &ServiceInfo_targetObject, SubState_B, 0, 0},
166      {    "service error", SubState_B, Punct_LPAREN,                0, "error",    0, 0, &ServiceError_targetObject, SubState_N, 0, 0},
167      {   "service option", SubState_B,  Punct_WHITE,       &getOption,   0,        0, 0,  &ServiceInfo_targetObject, SubState_C, 0, 0},
168      {"service extension", SubState_B, Punct_LPAREN,               0, "extension", 0, 0,    &Extension_targetObject, SubState_N, 0, 0},
169      { "label-mark close", SubState_B, Punct_RPAREN,                0, "l", "labels", 0, &LabelList_targetObject, SubState_C, Command_CLOSE|Command_CHAIN, 0},
170      {       "label-mark", SubState_B, Punct_WHITE|Punct_LPAREN,    0, "l", "labels", 0,     &Label_targetObject, SubState_N, Command_CHAIN, &ServiceInfo_clearOpts},
171      {     "option value", SubState_C, Punct_WHITE,    &getOptionValue,  0,        0, 0,  &ServiceInfo_targetObject, SubState_B, 0, 0},
172 
173      {            "close", SubState_D, Punct_ALL,                   0,        0,   0, 0,    &LabelList_targetObject, SubState_C, Command_MATCHANY|Command_CLOSE|Command_CHAIN, 0},
174      {         "re-enter", SubState_E, Punct_ALL,                   0,        0,   0, 0,  &ServiceInfo_targetObject, SubState_N, Command_MATCHANY|Command_CLOSE|Command_CHAIN, 0},
175      {        "to no-rat", SubState_F, Punct_ALL,                   0,        0,   0, 0,  &ServiceInfo_targetObject, SubState_G, Command_MATCHANY|Command_CLOSE|Command_CHAIN, 0},
176      {    "no-rat opener", SubState_G, Punct_ALL,                   0,        0,   0, 0, &ServiceNoRat_targetObject, SubState_N, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0}
177     };
178 PRIVATE TargetObject_t ServiceInfo_targetObject = {"ServiceInfo", ServiceInfo_open, &ServiceInfo_close, &ServiceInfo_destroy, ServiceInfo_stateTokens, raysize(ServiceInfo_stateTokens), CSLLTC_SERVICE};
179 
180 PRIVATE StateToken_t Label_stateTokens[] = {
181     /* A: fresh SingleLabel
182        C: route to Awkward from LabelTree and LabelError
183        D: from Awkward to LabelError */
184      {              "open", SubState_N,    Punct_ALL, 0,        0,    0,  0, &Label_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
185      { "single label mark", SubState_A,  Punct_WHITE, 0,  "l", "labels",  0,       &Label_targetObject, SubState_A, 0, 0}, /* stick around */
186      {   "tree label mark", SubState_A, Punct_LPAREN, 0,  "l", "labels",  0,   &LabelTree_targetObject, SubState_N, 0, 0},
187      {        "start tree", SubState_A, Punct_LPAREN, 0,         0,   0,  0,   &LabelTree_targetObject, SubState_N, 0, 0},
188      {       "label error", SubState_A, Punct_LPAREN, 0,   "error",   0,  0,  &LabelError_targetObject, SubState_N, 0, 0},
189      {"SingleLabel option", SubState_A, Punct_WHITE, &getOption, 0,   0,  0, &SingleLabel_targetObject, SubState_N, Command_CHAIN, 0},
190      {   "label extension", SubState_A, Punct_LPAREN, 0, "extension", 0,  0, &SingleLabel_targetObject, SubState_N, Command_CHAIN, 0},
191      {           "ratings", SubState_A, Punct_LPAREN, 0, "r", "ratings",  0, &SingleLabel_targetObject, SubState_N, Command_CHAIN, 0},
192 
193      {        "to awkward", SubState_C,    Punct_ALL, 0,        0,    0,  0,     &Awkward_targetObject, SubState_A, Command_MATCHANY|Command_CLOSE, 0},
194      {  "awkward to error", SubState_D,    Punct_ALL, 0,        0,    0,  0, &LabelError_targetObject, SubState_N, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0}
195     };
196 PRIVATE TargetObject_t Label_targetObject = {"Label", &Label_open, &Label_close, &Label_destroy, Label_stateTokens, raysize(Label_stateTokens), CSLLTC_LABEL};
197 
198 PRIVATE StateToken_t LabelTree_stateTokens[] = {
199     /* A: LabelTrees have no state */
200      {              "open", SubState_N, Punct_ALL,       0,        0, 0, 0, &LabelTree_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
201      {       "label error", SubState_A, Punct_LPAREN, 0, "error", 0,     0, &LabelError_targetObject, SubState_N, 0, 0},
202      {"SingleLabel option", SubState_A, Punct_WHITE, &getOption, 0,   0, 0, &SingleLabel_targetObject, SubState_N, Command_CHAIN, 0},
203      {        "ratingword", SubState_A, Punct_LPAREN, 0, "r", "ratings", 0, &SingleLabel_targetObject, SubState_N, Command_CHAIN, 0},
204      {       "end of tree", SubState_A, Punct_RPAREN,     0,       0, 0, 0, &Label_targetObject, SubState_C, Command_CLOSE|Command_CHAIN, 0}
205     };
206 PRIVATE TargetObject_t LabelTree_targetObject = {"LabelTree", &LabelTree_open, &LabelTree_close, &LabelTree_destroy, LabelTree_stateTokens, raysize(LabelTree_stateTokens), CSLLTC_LABTREE};
207 
208 PRIVATE StateToken_t SingleLabel_stateTokens[] = {
209     /* A: fresh SingleLabel
210        B: needs option value */
211      {           "open", SubState_N, Punct_ALL, 0,                  0, 0,  0, &SingleLabel_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
212      {"label extension", SubState_A, Punct_LPAREN,     0, "extension", 0,  0,   &Extension_targetObject, SubState_N, 0, 0},
213      {   "label option", SubState_A,  Punct_WHITE, &getOption,      0, 0,  0, &SingleLabel_targetObject, SubState_B, 0, 0},
214      {     "ratingword", SubState_A, Punct_LPAREN,     0, "r", "ratings",  0, &LabelRating_targetObject, SubState_N, 0, 0},
215      {   "option value", SubState_B,  Punct_WHITE, &getOptionValue, 0, 0,  0, &SingleLabel_targetObject, SubState_A, 0, 0}
216     };
217 PRIVATE TargetObject_t SingleLabel_targetObject = {"SingleLabel", &SingleLabel_open, &SingleLabel_close, &SingleLabel_destroy, SingleLabel_stateTokens, raysize(SingleLabel_stateTokens), CSLLTC_SINGLE};
218 
219 PRIVATE StateToken_t LabelRating_stateTokens[] = {
220     /* A: looking for transmit name
221        B: looking for value
222        C: return from range (either creates a new rating or ends)
223        D: close and re-open */
224      {             "open", SubState_N,    Punct_ALL,              0,        0, 0, 0, &LabelRating_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
225      {  "id before value", SubState_A,  Punct_WHITE,    &LabelRating_getId, 0, 0, 0,      &LabelRating_targetObject, SubState_B, 0, 0},
226      {  "id before range", SubState_A, Punct_LPAREN,    &LabelRating_getId, 0, 0, 0, &LabelRatingRange_targetObject, SubState_N, 0, 0},
227      {       "value next", SubState_B,  Punct_WHITE, &LabelRating_getValue, 0, 0, 0,      &LabelRating_targetObject, SubState_D, 0, 0}, /* opener must close last rating first */
228      {      "value close", SubState_B, Punct_RPAREN, &LabelRating_getValue, 0, 0, 0, 0, SubState_X, Command_CLOSE, &LabelRating_next},
229      {            "close", SubState_C, Punct_RPAREN,                     0, 0, 0, 0, 0, SubState_X, Command_CLOSE, &LabelRating_next},
230      {"value after range", SubState_C, Punct_WHITE|Punct_LPAREN, &hasToken, 0, 0, 0, &LabelRating_targetObject, SubState_D, Command_CHAIN, 0}, /* opener must close last rating first */
231 
232      {         "re-enter", SubState_D, Punct_ALL,                 0,        0, 0, 0, &LabelRating_targetObject, SubState_N, Command_MATCHANY|Command_CLOSE|Command_CHAIN, 0}
233     };
234 PRIVATE TargetObject_t LabelRating_targetObject = {"LabelRating", &LabelRating_open, &LabelRating_close, &LabelRating_destroy, LabelRating_stateTokens, raysize(LabelRating_stateTokens), CSLLTC_RATING};
235 
236 PRIVATE StateToken_t LabelRatingRange_stateTokens[] = {
237      {       "open", SubState_N,    Punct_ALL,              0,        0, 0, 0, &LabelRatingRange_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
238      { "range data", SubState_A,  Punct_WHITE, &LabelRatingRange_get, 0, 0, 0, &LabelRatingRange_targetObject, SubState_A, 0, 0},
239      {"range close", SubState_A, Punct_RPAREN, &LabelRatingRange_get, 0, 0, 0,      &LabelRating_targetObject, SubState_C, Command_CLOSE, 0}
240     };
241 PRIVATE TargetObject_t LabelRatingRange_targetObject = {"LabelRatingRange", &LabelRatingRange_open, &LabelRatingRange_close, &LabelRatingRange_destroy, LabelRatingRange_stateTokens, raysize(LabelRatingRange_stateTokens), CSLLTC_RANGE};
242 
243 /* Awkward assumes that the current Label has been closed. It decides whether to chain to LabelTree, Label, or ServiceInfo */
244 PRIVATE StateToken_t Awkward_stateTokens[] = {
245      {           "open", SubState_N,    Punct_ALL, 0,          0,  0, 0, &Awkward_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
246      {     "start tree", SubState_A, Punct_LPAREN,          0, 0,  0, 0,               &LabelTree_targetObject, SubState_N, 0, 0},
247      {    "label error", SubState_A, Punct_LPAREN, 0,    "error",  0, 0,                 &Awkward_targetObject, SubState_B, 0, 0},
248      {   "label option", SubState_A,  Punct_WHITE, &getOption, 0,  0, 0,       &Label_targetObject, SubState_N, Command_CHAIN, 0},
249      {"label extension", SubState_A, Punct_LPAREN, 0, "extension", 0, 0,       &Label_targetObject, SubState_N, Command_CHAIN, 0},
250      {         "rating", SubState_A, Punct_LPAREN, 0, "r", "ratings", 0,       &Label_targetObject, SubState_N, Command_CHAIN, 0},
251      { "new service id", SubState_A,  Punct_WHITE,  &isQuoted, 0,  0, 0, &ServiceInfo_targetObject, SubState_E, Command_CHAIN, 0},
252      {          "close", SubState_A, Punct_RPAREN,          0, 0,  0, 0, &ServiceInfo_targetObject, SubState_D, Command_CHAIN, 0}, /* close of LabelList */
253 
254      {       "req-denied", SubState_B,  Punct_WHITE, 0, "request-denied", 0, 0, &Label_targetObject, SubState_D, Command_CHAIN, 0},
255      { "req-denied close", SubState_B, Punct_RPAREN, 0, "request-denied", 0, 0, &Label_targetObject, SubState_D, Command_CHAIN, 0},
256      {      "not-labeled", SubState_B,  Punct_WHITE, 0,    "not-labeled", 0, 0, &Label_targetObject, SubState_D, Command_CHAIN, 0},
257      {"not-labeled close", SubState_B, Punct_RPAREN, 0,    "not-labeled", 0, 0, &Label_targetObject, SubState_D, Command_CHAIN, 0},
258      {       "no-ratings", SubState_B,  Punct_WHITE, 0, "no-ratings", 0, 0, &ServiceInfo_targetObject, SubState_F, Command_CHAIN, 0},
259      { "no-ratings close", SubState_B, Punct_RPAREN, 0, "no-ratings", 0, 0, &ServiceInfo_targetObject, SubState_F, Command_CHAIN, 0}
260     };
261 PRIVATE TargetObject_t Awkward_targetObject = {"Awkward", &Awkward_open, &Awkward_close, &Awkward_destroy, Awkward_stateTokens, raysize(Awkward_stateTokens), 0};
262 
263 /* error parsing states */
264 PRIVATE StateToken_t ServiceNoRat_stateTokens[] = {
265      {             "open", SubState_N,    Punct_ALL,   0,            0, 0, 0, &ServiceNoRat_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
266      {       "no-ratings", SubState_A,  Punct_WHITE,   0, "no-ratings", 0, 0, &ServiceNoRat_targetObject, SubState_B, 0, 0},
267      { "no-ratings close", SubState_A, Punct_RPAREN,   0, "no-ratings", 0, 0,    &ServiceInfo_targetObject, SubState_D, Command_CLOSE|Command_CHAIN, 0},
268      {      "explanation", SubState_B,  Punct_WHITE, &error_getExpl, 0, 0, 0, &ServiceNoRat_targetObject, SubState_B, 0, 0},
269      {"explanation close", SubState_B, Punct_RPAREN, &error_getExpl, 0, 0, 0,    &ServiceInfo_targetObject, SubState_D, Command_CLOSE|Command_CHAIN, 0}
270     };
271 PRIVATE TargetObject_t ServiceNoRat_targetObject = {"ServiceNoRat", &error_open, &error_close, &error_destroy, ServiceNoRat_stateTokens, raysize(ServiceNoRat_stateTokens), CSLLTC_NORAT};
272 
273 PRIVATE StateToken_t ServiceError_stateTokens[] = {
274      {                 "open", SubState_N,    Punct_ALL, 0,                    0, 0, 0, &ServiceError_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
275      {           "req-denied", SubState_A,  Punct_WHITE, 0,     "request-denied", 0, 0, &ServiceError_targetObject, SubState_B, 0, 0},
276      {     "req-denied close", SubState_A, Punct_RPAREN, 0,     "request-denied", 0, 0,    &ServiceInfo_targetObject, SubState_D, Command_CLOSE|Command_CHAIN, 0},
277      {      "service-unavail", SubState_A,  Punct_WHITE, 0,"service-unavailable", 0, 0, &ServiceError_targetObject, SubState_B, 0, 0},
278      {"service-unavail close", SubState_A, Punct_RPAREN, 0,"service-unavailable", 0, 0,    &ServiceInfo_targetObject, SubState_D, Command_CLOSE|Command_CHAIN, 0},
279      {          "explanation", SubState_B,  Punct_WHITE, &error_getExpl,       0, 0, 0, &ServiceError_targetObject, SubState_B, 0, 0},
280      {    "explanation close", SubState_B, Punct_RPAREN, &error_getExpl,       0, 0, 0,    &ServiceInfo_targetObject, SubState_D, Command_CLOSE|Command_CHAIN, 0}
281     };
282 PRIVATE TargetObject_t ServiceError_targetObject = {"ServiceError", &error_open, &error_close, &error_destroy, ServiceError_stateTokens, raysize(ServiceError_stateTokens), CSLLTC_SRVERR};
283 
284 PRIVATE StateToken_t LabelError_stateTokens[] = {
285      {             "open", SubState_N,    Punct_ALL, 0,                0, 0, 0, &LabelError_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
286      {       "req-denied", SubState_A,  Punct_WHITE, 0, "request-denied", 0, 0, &LabelError_targetObject, SubState_B, 0, 0},
287      { "req-denied close", SubState_A, Punct_RPAREN, 0, "request-denied", 0, 0,    &Label_targetObject, SubState_C, Command_CLOSE|Command_CHAIN, 0},
288      {      "not-labeled", SubState_A,  Punct_WHITE, 0,    "not-labeled", 0, 0, &LabelError_targetObject, SubState_B, 0, 0},
289      {"not-labeled close", SubState_A, Punct_RPAREN, 0,    "not-labeled", 0, 0,    &Label_targetObject, SubState_C, Command_CLOSE|Command_CHAIN, 0},
290      {      "explanation", SubState_B,  Punct_WHITE, &error_getExpl,   0, 0, 0, &LabelError_targetObject, SubState_B, 0, 0},
291      {"explanation close", SubState_B, Punct_RPAREN, &error_getExpl,   0, 0, 0,    &Label_targetObject, SubState_C, Command_CLOSE|Command_CHAIN, 0}
292     };
293 PRIVATE TargetObject_t LabelError_targetObject = {"LabelError", &error_open, &error_close, &error_destroy, LabelError_stateTokens, raysize(LabelError_stateTokens), CSLLTC_LABERR};
294 
295 PRIVATE StateToken_t Extension_stateTokens[] = {
296     /* A: looking for mand/opt
297        B: looking for URL
298        C: back from ExtensionData */
299      {      "open", SubState_N,    Punct_ALL,        0,           0, 0, 0, &Extension_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
300 	 { "mandatory", SubState_A,  Punct_WHITE,        0, "mandatory", 0, 0, &Extension_targetObject, SubState_B, 0, &Extension_mandatory},
301      {  "optional", SubState_A,  Punct_WHITE,        0,  "optional", 0, 0, &Extension_targetObject, SubState_B, 0, 0},
302      {       "URL", SubState_B,  Punct_WHITE,  &Extension_getURL, 0, 0, 0, &ExtensionData_targetObject, SubState_N, 0, 0},
303      {  "URL open", SubState_B, Punct_LPAREN,  &Extension_getURL, 0, 0, 0, &ExtensionData_targetObject, SubState_N, Command_CHAIN|Command_NOTOKEN, 0},
304      { "URL close", SubState_B, Punct_RPAREN,  &Extension_getURL, 0, 0, 0, 0, SubState_X, Command_CLOSE, &Extension_next},
305 
306      { "more data", SubState_C, Punct_WHITE|Punct_LPAREN|Punct_RPAREN, &hasToken, 0, 0, 0, &ExtensionData_targetObject, SubState_N, Command_CHAIN, 0},
307      {      "nest", SubState_C, Punct_LPAREN,           0,         0, 0, 0, &ExtensionData_targetObject, SubState_N, Command_CHAIN, 0},
308      {     "close", SubState_C, Punct_RPAREN,           0,         0, 0, 0, 0, SubState_X, Command_CLOSE, &Extension_next}
309     };
310 PRIVATE TargetObject_t Extension_targetObject = {"Extension", &Extension_open, &Extension_close, &Extension_destroy, Extension_stateTokens, raysize(Extension_stateTokens), CSLLTC_EXTEN};
311 
312 PRIVATE StateToken_t ExtensionData_stateTokens[] = {
313     /* A: looking for data
314        B: back from recursive ExtensionData (identical to Extension B) */
315      {      "open", SubState_N,    Punct_ALL,               0,        0, 0, 0, &ExtensionData_targetObject, SubState_A, Command_MATCHANY|Command_OPEN|Command_CHAIN, 0},
316      {    "lparen", SubState_A, Punct_LPAREN,                      0, 0, 0, 0, &ExtensionData_targetObject, SubState_N, 0, 0},
317      {     "close", SubState_A, Punct_RPAREN,                      0, 0, 0, 0, 0, SubState_X, Command_CLOSE, &ExtensionData_next},
318 	 {      "data", SubState_A, Punct_WHITE, &ExtensionData_getData, 0, 0, 0, 0, SubState_X, Command_CLOSE, &ExtensionData_next},
319 	 {"data punct", SubState_A, Punct_LPAREN|Punct_RPAREN, &ExtensionData_getData, 0, 0, 0, 0, SubState_X, Command_CLOSE|Command_CHAIN|Command_NOTOKEN, &ExtensionData_next},
320 
321      { "more data", SubState_B, Punct_WHITE|Punct_LPAREN|Punct_RPAREN, &hasToken, 0, 0, 0, &ExtensionData_targetObject, SubState_N, Command_CHAIN, 0},
322      {      "nest", SubState_B, Punct_LPAREN,           0,         0, 0, 0, &ExtensionData_targetObject, SubState_N, Command_CHAIN, 0},
323 	 {     "close", SubState_B, Punct_RPAREN,           0,         0, 0, 0, 0, SubState_X, Command_CLOSE, &ExtensionData_next}
324     };
325 PRIVATE TargetObject_t ExtensionData_targetObject = {"ExtensionData", &ExtensionData_open, &ExtensionData_close, &ExtensionData_destroy, ExtensionData_stateTokens, raysize(ExtensionData_stateTokens), CSLLTC_EXTDATA};
326 
327 /* CSParse_doc end */
328 /* S T A T E   A S S O C I A T I O N - associate a CSLabel with the label list data
329    The label list data is kept around until all states referencing it are destroyed */
330 typedef struct {
331     CSLabel_t * pCSLabel;
332     CSLLData_t * pCSLLData;
333     } CSLabelAssoc_t;
334 
335 PRIVATE HTList * CSLabelAssocs = 0;
336 
CSLabelAssoc_add(CSLabel_t * pCSLabel,CSLLData_t * pCSLLData)337 PRIVATE void CSLabelAssoc_add(CSLabel_t * pCSLabel, CSLLData_t * pCSLLData)
338 {
339     CSLabelAssoc_t * pElement;
340     if ((pElement = (CSLabelAssoc_t *) HT_CALLOC(1, sizeof(CSLabelAssoc_t))) == NULL)
341         HT_OUTOFMEM("CSLabelAssoc_t");
342     pElement->pCSLabel = pCSLabel;
343     pElement->pCSLLData = pCSLLData;
344     if (!CSLabelAssocs)
345         CSLabelAssocs = HTList_new();
346     HTList_appendObject(CSLabelAssocs, (void *)pElement);
347 }
348 
CSLabelAssoc_findByData(CSLLData_t * pCSLLData)349 PRIVATE CSLabelAssoc_t * CSLabelAssoc_findByData(CSLLData_t * pCSLLData)
350 {
351     HTList * assocs = CSLabelAssocs;
352     CSLabelAssoc_t * pElement;
353     while ((pElement = (CSLabelAssoc_t *) HTList_nextObject(assocs)))
354         if (pElement->pCSLLData == pCSLLData)
355             return pElement;
356     return 0;
357 }
358 
CSLabelAssoc_findByState(CSLabel_t * pCSLabel)359 PRIVATE CSLabelAssoc_t * CSLabelAssoc_findByState(CSLabel_t * pCSLabel)
360 {
361     HTList * assocs = CSLabelAssocs;
362     CSLabelAssoc_t * pElement;
363     while ((pElement = (CSLabelAssoc_t *) HTList_nextObject(assocs)))
364         if (pElement->pCSLabel == pCSLabel)
365             return pElement;
366     return 0;
367 }
368 
CSLabelAssoc_removeByState(CSLabel_t * pCSLabel)369 PRIVATE void CSLabelAssoc_removeByState(CSLabel_t * pCSLabel)
370 {
371     CSLabelAssoc_t * pElement = CSLabelAssoc_findByState(pCSLabel);
372     if (!pElement)
373         return;
374     HTList_removeObject(CSLabelAssocs, (void *)pElement);
375    HT_FREE(pElement);
376 }
377 
378 /* P R I V A T E   C O N S T R U C T O R S / D E S T R U C T O R S */
379 /* These serve the public constructors
380  */
LabelError_new(void)381 PRIVATE LabelError_t * LabelError_new(void)
382 {
383     LabelError_t * me;
384     if ((me = (LabelError_t *) HT_CALLOC(1, sizeof(LabelError_t))) == NULL)
385         HT_OUTOFMEM("LabelError_t");
386     me->explanations = HTList_new();
387     return me;
388 }
389 
LabelError_free(LabelError_t * me)390 PRIVATE void LabelError_free(LabelError_t * me)
391 {
392     char * explanation;
393     if (!me)
394         return;
395     while ((explanation = (char *) HTList_removeLastObject(me->explanations)))
396         HT_FREE(explanation);
397     HT_FREE(me);
398 }
399 
LabelOptions_new(LabelOptions_t * pParentLabelOptions)400 PRIVATE LabelOptions_t * LabelOptions_new(LabelOptions_t * pParentLabelOptions)
401 {
402     LabelOptions_t * me;
403     if ((me = (LabelOptions_t *) HT_CALLOC(1, sizeof(LabelOptions_t))) == NULL)
404         HT_OUTOFMEM("LabelOptions_t");
405     me->pParentLabelOptions = pParentLabelOptions;
406     return me;
407 }
408 
LabelOptions_free(LabelOptions_t * me)409 PRIVATE void LabelOptions_free(LabelOptions_t * me)
410 {
411 	char * comment;
412     DVal_clear(&me->at);
413     SVal_clear(&me->by);
414     SVal_clear(&me->complete_label);
415     BVal_clear(&me->generic);
416     SVal_clear(&me->fur);
417     SVal_clear(&me->MIC_md5);
418     DVal_clear(&me->on);
419     SVal_clear(&me->signature_PKCS);
420     DVal_clear(&me->until);
421     while ((comment = HTList_removeLastObject(me->comments)))
422 	HT_FREE(comment);
423     HT_FREE(me);
424 }
425 
ExtensionData_new(void)426 PRIVATE ExtensionData_t * ExtensionData_new(void)
427 {
428     ExtensionData_t * me;
429     if ((me = (ExtensionData_t *) HT_CALLOC(1, sizeof(ExtensionData_t))) == NULL)
430         HT_OUTOFMEM("ExtensionData_t");
431     return me;
432 }
433 
ExtensionData_free(ExtensionData_t * me)434 PRIVATE void ExtensionData_free(ExtensionData_t * me)
435 {
436     ExtensionData_t * pExtensionData;
437     while ((pExtensionData = (ExtensionData_t *) HTList_removeLastObject(me->moreData)))
438         ExtensionData_free(pExtensionData);
439     HT_FREE(me->text);
440     HT_FREE(me);
441 }
442 
Extension_new(void)443 PRIVATE Extension_t * Extension_new(void)
444 {
445     Extension_t * me;
446     if ((me = (Extension_t *) HT_CALLOC(1, sizeof(Extension_t))) == NULL)
447         HT_OUTOFMEM("Extension_t");
448     return me;
449 }
450 
Extension_free(Extension_t * me)451 PRIVATE void Extension_free(Extension_t * me)
452 {
453     ExtensionData_t * pExtensionData;
454     while ((pExtensionData = (ExtensionData_t *) HTList_removeLastObject(me->extensionData)))
455         ExtensionData_free(pExtensionData);
456     SVal_clear(&me->url);
457     HT_FREE(me);
458 }
459 
LabelRating_new(void)460 PRIVATE LabelRating_t * LabelRating_new(void)
461 {
462     LabelRating_t * me;
463     if ((me = (LabelRating_t *) HT_CALLOC(1, sizeof(LabelRating_t))) == NULL)
464         HT_OUTOFMEM("LabelRating_t");
465 /*  don't initialize HTList me->ranges as it may be just a value */
466     return me;
467 }
468 
LabelRating_free(LabelRating_t * me)469 PRIVATE void LabelRating_free(LabelRating_t * me)
470 {
471     Range_t * pRange;
472     while ((pRange = (Range_t *) HTList_removeLastObject(me->ranges)))
473         HT_FREE(pRange);
474     SVal_clear(&me->identifier);
475     HT_FREE(me);
476 }
477 
SingleLabel_new(LabelOptions_t * pLabelOptions,LabelOptions_t * pParentLabelOptions)478 PRIVATE SingleLabel_t * SingleLabel_new(LabelOptions_t * pLabelOptions, LabelOptions_t * pParentLabelOptions)
479 {
480     SingleLabel_t * me;
481     if ((me = (SingleLabel_t *) HT_CALLOC(1, sizeof(SingleLabel_t))) == NULL)
482         HT_OUTOFMEM("SingleLabel_t");
483     me->labelRatings = HTList_new();
484     me->pLabelOptions = pLabelOptions ? pLabelOptions : LabelOptions_new(pParentLabelOptions);
485     return me;
486 }
487 
SingleLabel_free(SingleLabel_t * me)488 PRIVATE void SingleLabel_free(SingleLabel_t * me)
489 {
490     LabelRating_t * pLabelRating;
491     while ((pLabelRating = (LabelRating_t *) HTList_removeLastObject(me->labelRatings)))
492         LabelRating_free(pLabelRating);
493     LabelOptions_free(me->pLabelOptions);
494     HT_FREE(me);
495 }
496 
Label_new(void)497 PRIVATE Label_t * Label_new(void)
498 {
499     Label_t * me;
500     if ((me = (Label_t *) HT_CALLOC(1, sizeof(Label_t))) == NULL)
501         HT_OUTOFMEM("Label_t");
502     /* dont initialize HTList me->singleLabels */
503     return me;
504 }
505 
Label_free(Label_t * me)506 PRIVATE void Label_free(Label_t * me)
507 {
508     SingleLabel_t * pSingleLabel;
509     if (me->pSingleLabel)
510         SingleLabel_free(me->pSingleLabel);
511     else    /* if both of these are (erroneously) defined, mem checkers will pick it up */
512         while ((pSingleLabel = (SingleLabel_t *) HTList_removeLastObject(me->singleLabels)))
513             SingleLabel_free(pSingleLabel);
514     LabelError_free(me->pLabelError);
515     HT_FREE(me);
516 }
517 
ServiceInfo_new()518 PRIVATE ServiceInfo_t * ServiceInfo_new()
519 {
520     ServiceInfo_t * me;
521     if ((me = (ServiceInfo_t *) HT_CALLOC(1, sizeof(ServiceInfo_t))) == NULL)
522         HT_OUTOFMEM("ServiceInfo_t");
523     me->labels = HTList_new();
524     me->pLabelOptions = LabelOptions_new(0);
525     return me;
526 }
527 
ServiceInfo_free(ServiceInfo_t * me)528 PRIVATE void ServiceInfo_free(ServiceInfo_t * me)
529 {
530     Label_t * pLabel;
531     while ((pLabel = (Label_t *) HTList_removeLastObject(me->labels)))
532         Label_free(pLabel);
533     SVal_clear(&me->rating_service);
534     LabelOptions_free(me->pLabelOptions);
535     LabelError_free(me->pLabelError);
536     HT_FREE(me);
537 }
538 
CSLLData_new(void)539 PRIVATE CSLLData_t * CSLLData_new(void)
540 {
541     CSLLData_t * me;
542     if ((me = (CSLLData_t *) HT_CALLOC(1, sizeof(CSLLData_t))) == NULL)
543         HT_OUTOFMEM("CSLLData_t");
544     me->serviceInfos = HTList_new();
545     return me;
546 }
547 
CSLLData_free(CSLLData_t * me)548 PRIVATE void CSLLData_free(CSLLData_t * me)
549 {
550     ServiceInfo_t * pServiceInfo;
551     if (CSLabelAssoc_findByData(me))
552         return;
553     while ((pServiceInfo = (ServiceInfo_t *) HTList_removeLastObject(me->serviceInfos)))
554         ServiceInfo_free(pServiceInfo);
555     FVal_clear(&me->version);
556     LabelError_free(me->pLabelError);
557     HT_FREE(me);
558 }
559 
560 /* P U B L I C   C O N S T R U C T O R S / D E S T R U C T O R S */
CSLabel_new(CSLLData_t * pCSLLData,LabelTargetCallback_t * pLabelTargetCallback,LLErrorHandler_t * pLLErrorHandler)561 PUBLIC CSLabel_t * CSLabel_new(CSLLData_t * pCSLLData, LabelTargetCallback_t * pLabelTargetCallback,
562 								   LLErrorHandler_t * pLLErrorHandler)
563 {
564     CSLabel_t * me;
565     if ((me = (CSLabel_t *) HT_CALLOC(1, sizeof(CSLabel_t))) == NULL)
566         HT_OUTOFMEM("CSLabel_t");
567     me->pCSLLData = pCSLLData;
568     me->pLabelTargetCallback = pLabelTargetCallback;
569     me->pLLErrorHandler = pLLErrorHandler;
570     CSLabelAssoc_add(me, pCSLLData);
571     return me;
572 }
573 
CSLabel_copy(CSLabel_t * old)574 PUBLIC CSLabel_t * CSLabel_copy(CSLabel_t * old)
575 {
576     CSLabel_t * me = CSLabel_new(old->pCSLLData, old->pLabelTargetCallback, old->pLLErrorHandler);
577     memcpy(me, old, sizeof(CSLabel_t));
578     return me;
579 }
580 
CSLabel_free(CSLabel_t * me)581 PUBLIC void CSLabel_free(CSLabel_t * me)
582 {
583     CSLLData_t * pCSLLData = me->pCSLLData;
584     CSLabelAssoc_removeByState(me);
585     HT_FREE(me);
586     CSLLData_free(pCSLLData);
587 }
588 
CSLabel_getCSLLData(CSLabel_t * me)589 PUBLIC CSLLData_t * CSLabel_getCSLLData(CSLabel_t * me)
590     {return me->pCSLLData;}
CSLabel_getLabelError(CSLabel_t * pCSLabel)591 PUBLIC LabelError_t * CSLabel_getLabelError(CSLabel_t * pCSLabel)
592     {return pCSLabel->pCurrentLabelError;}
CSLabel_getLabelOptions(CSLabel_t * pCSLabel)593 PUBLIC LabelOptions_t * CSLabel_getLabelOptions(CSLabel_t * pCSLabel)
594     {return pCSLabel->pCurrentLabelOptions;}
CSLabel_getServiceInfo(CSLabel_t * pCSLabel)595 PUBLIC ServiceInfo_t * CSLabel_getServiceInfo(CSLabel_t * pCSLabel)
596     {return pCSLabel->pCurrentServiceInfo;}
CSLabel_getServiceName(CSLabel_t * pCSLabel)597 PUBLIC char * CSLabel_getServiceName(CSLabel_t * pCSLabel)
598     {return pCSLabel->pCurrentServiceInfo ?
599        SVal_value(&pCSLabel->pCurrentServiceInfo->rating_service): 0;}
CSLabel_getLabel(CSLabel_t * pCSLabel)600 PUBLIC Label_t * CSLabel_getLabel(CSLabel_t * pCSLabel)
601     {return pCSLabel->pCurrentLabel;}
CSLabel_getLabelNumber(CSLabel_t * pCSLabel)602 PUBLIC int CSLabel_getLabelNumber(CSLabel_t * pCSLabel)
603     {return pCSLabel->currentLabelNumber;}
CSLabel_getSingleLabel(CSLabel_t * pCSLabel)604 PUBLIC SingleLabel_t * CSLabel_getSingleLabel(CSLabel_t * pCSLabel)
605     {return pCSLabel->pCurrentSingleLabel;}
CSLabel_getLabelRating(CSLabel_t * pCSLabel)606 PUBLIC LabelRating_t * CSLabel_getLabelRating(CSLabel_t * pCSLabel)
607     {return pCSLabel->pCurrentLabelRating;}
CSLabel_getRatingName(CSLabel_t * pCSLabel)608 PUBLIC char * CSLabel_getRatingName(CSLabel_t * pCSLabel)
609     {return pCSLabel->pCurrentLabelRating ?
610        SVal_value(&pCSLabel->pCurrentLabelRating->identifier): 0;}
CSLabel_getLabelRatingRange(CSLabel_t * pCSLabel)611 PUBLIC Range_t * CSLabel_getLabelRatingRange(CSLabel_t * pCSLabel)
612     {return pCSLabel->pCurrentRange;}
CSLabel_getRatingStr(CSLabel_t * pCSLabel)613 PUBLIC char * CSLabel_getRatingStr(CSLabel_t * pCSLabel)
614 {
615     HTChunk * pChunk;
616     HTList * ranges;
617     Range_t * curRange;
618     FVal_t fVal;
619     int count = 0;
620     fVal = CSLabel_getLabelRating(pCSLabel)->value;
621     if (FVal_initialized(&fVal))
622         return FVal_toStr(&fVal);
623     pChunk = HTChunk_new(20);
624     ranges = CSLabel_getLabelRating(pCSLabel)->ranges;
625     while ((curRange = (Range_t *) HTList_nextObject(ranges))) {
626         char * ptr;
627 	count++;
628 	ptr = Range_toStr(curRange);
629 	if (count > 1)
630 	    HTChunk_puts(pChunk, " ");
631 	HTChunk_puts(pChunk, ptr);
632 	HT_FREE(ptr);
633     }
634     return HTChunk_toCString(pChunk);
635 }
636 
CSParse_newLabel(LabelTargetCallback_t * pLabelTargetCallback,LLErrorHandler_t * pLLErrorHandler)637 PUBLIC CSParse_t * CSParse_newLabel(LabelTargetCallback_t * pLabelTargetCallback,
638 				    LLErrorHandler_t * pLLErrorHandler)
639 {
640     CSParse_t * me = CSParse_new();
641     me->pParseContext->engineOf = &CSParse_targetParser;
642     me->pParseContext->pTargetChangeCallback = &targetChangeCallback;
643     me->pParseContext->pParseErrorHandler = &parseErrorHandler;
644     me->target.pCSLabel = CSLabel_new(CSLLData_new(), pLabelTargetCallback, pLLErrorHandler);
645     me->pTargetObject = &LabelList_targetObject;
646     me->currentSubState = SubState_N;
647     return me;
648 }
649 
CSParse_getLabel(CSParse_t * me)650 PUBLIC CSLabel_t * CSParse_getLabel(CSParse_t * me)
651 {
652     return (me->target.pCSLabel);
653 }
654 
CSParse_deleteLabel(CSParse_t * pCSParse)655 PUBLIC BOOL CSParse_deleteLabel(CSParse_t * pCSParse)
656 {
657     CSLabel_t * me = GetCSLabel(pCSParse);
658     CSLLData_free(CSLabel_getCSLLData(me));
659     CSLabel_free(me);
660 	CSParse_delete(pCSParse);
661     return YES;
662 }
663 
664 /* D E F A U L T   P A R S I N G   H A N D L E R S */
targetChangeCallback(CSParse_t * pCSParse,TargetObject_t * pTargetObject,CSParseTC_t target,BOOL closed,void * pVoid)665 PRIVATE StateRet_t targetChangeCallback(CSParse_t * pCSParse, TargetObject_t * pTargetObject, CSParseTC_t target, BOOL closed, void * pVoid)
666 {
667 
668 	CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
669 	if (pCSLabel->pLabelTargetCallback)
670 		return (*pCSLabel->pLabelTargetCallback)(pCSLabel, pCSParse, (CSLLTC_t)target, closed, pVoid);
671     return StateRet_OK;
672 }
673 
parseErrorHandler(CSParse_t * pCSParse,const char * token,char demark,StateRet_t errorCode)674 PRIVATE StateRet_t parseErrorHandler(CSParse_t * pCSParse, const char * token, char demark, StateRet_t errorCode)
675 {
676 	CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
677 	if (pCSLabel->pLLErrorHandler)
678 		return (*pCSLabel->pLLErrorHandler)(pCSLabel, pCSParse, token, demark, errorCode);
679   return errorCode;
680 }
681 
682 /* CSParse_doc methods */
683 /* P A R S I N G   S T A T E   F U N C T I O N S */
684 #ifndef NO_CHAR_TEST
charSetOK(CSParse_t * pCSParse,char * checkMe,CharSet_t set)685 PRIVATE BOOL charSetOK(CSParse_t * pCSParse, char * checkMe, CharSet_t set)
686 {
687     for (;*checkMe;checkMe++) {
688         if (set & CharSet_ALPHAS &&
689             ((*checkMe >= 'A' && *checkMe <= 'Z') ||
690              (*checkMe >= 'a' && *checkMe <= 'z')))
691             continue;
692         if (set & CharSet_DIGITS &&
693             ((*checkMe >= '0' && *checkMe <= '9') || *checkMe == '.'))
694             continue;
695         if (set & CharSet_PLUSMINUS &&
696             ((*checkMe == '+' || *checkMe == '-')))
697             continue;
698         if (set & CharSet_FORSLASH &&
699             *checkMe == '/')
700             continue;
701         if (set & CharSet_BASE64_EXTRAS &&
702             ((*checkMe == '+' || *checkMe == '/' || *checkMe == '=')))
703             continue;
704         if (set & CharSet_DATE_EXTRAS &&
705             (*checkMe == '.' || *checkMe == ':' ||
706              *checkMe == '-' || *checkMe == 'T'))
707             continue;
708 		/* RFC1738:2.1:"+.-","#%",";/"?:@=&" 2.2:"$-_.+!*'()," */
709         if (set & CharSet_URL_EXTRAS &&
710             (*checkMe == ':' || *checkMe == '?' ||
711              *checkMe == '#' || *checkMe == '%' ||
712              *checkMe == '/' || *checkMe == '.' ||
713              *checkMe == '-' || *checkMe == '_' ||
714 	     *checkMe == '~' || *checkMe == '\\'))
715             continue;
716 /* '.' | ' ' | ',' | ';' | ':' | '&' | '=' | '?' | '!' | '*' | '~' | '@' | '#' */
717         if (set & CharSet_EXTENS &&
718             (*checkMe == '.' || *checkMe == ' ' ||
719              *checkMe == ',' || *checkMe == ';' ||
720              *checkMe == ':' || *checkMe == '&' ||
721              *checkMe == '=' || *checkMe == '?' ||
722              *checkMe == '!' || *checkMe == '*' ||
723              *checkMe == '~' || *checkMe == '@' ||
724              *checkMe == '#' || *checkMe == '\''||
725              *checkMe == '/' || *checkMe == '-'))
726             continue;
727         pCSParse->pParseContext->pTokenError = checkMe;
728         return FALSE;
729     }
730     return TRUE;
731 }
732 #endif /* !NO_CHAR_TEST */
733 
isQuoted(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)734 PRIVATE StateRet_t isQuoted(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
735 {
736     ParseContext_t * pParseContext = pCSParse->pParseContext;
737     if (!pParseContext->observedQuotes)
738         return StateRet_WARN_NO_MATCH;
739     if (Punct_badDemark(pStateToken->validPunctuation, demark))
740         return StateRet_WARN_BAD_PUNCT;
741     return StateRet_OK;
742 }
743 
hasToken(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)744 PRIVATE StateRet_t hasToken(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
745 {
746     return token ? StateRet_OK : StateRet_WARN_NO_MATCH;
747 }
748 #if 0
749 PRIVATE StateRet_t clearToken(CSParse_t * pCSParse, char * token, char demark)
750 {
751     HTChunk_clear(pCSParse->token);
752     return StateRet_OK;
753 }
754 #endif
755 /* getOption - see if token matches an option.
756 This may be called by:
757     ServiceInfo: add option to existent options, pCurrentLabelError is set by ServiceInfo_open
758     Label: kick off SingleLabel - SingleLabel_new(), pCurrentLabelError is 0
759     SingleLabel: add another option to existent options, pCurrentLabelError is set by SingleLabel_open
760  */
761 #define CSOffsetOf(s,m) (size_t)&(((s *)0)->m)
762 #define CHECK_OPTION_TOKEN_BVAL1(text, pointer) \
763 if (!strcasecomp(token, text)) {\
764     pCSParse->pParseContext->valTarget.pTargetBVal = pointer;\
765     pCSParse->pParseContext->valType = ValType_BVAL;\
766     break;\
767 }
768 
769 #define CHECK_OPTION_TOKEN_FVAL1(text, pointer) \
770 if (!strcasecomp(token, text)) {\
771     pCSParse->pParseContext->valTarget.pTargetFVal = pointer;\
772     pCSParse->pParseContext->valType = ValType_FVAL;\
773     break;\
774 }
775 
776 #define CHECK_OPTION_TOKEN_SVAL1(text, pointer, charSet) \
777 if (!strcasecomp(token, text)) {\
778     pCSParse->pParseContext->valTarget.pTargetSVal = pointer;\
779     pCSParse->pParseContext->valType = ValType_SVAL;\
780     SET_CHAR_SET(charSet)\
781     break;\
782 }
783 
784 #define CHECK_OPTION_TOKEN_DVAL1(text, pointer) \
785 if (!strcasecomp(token, text)) {\
786     pCSParse->pParseContext->valTarget.pTargetDVal = pointer;\
787     pCSParse->pParseContext->valType = ValType_DVAL;\
788     break;\
789 }
790 
getOption(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)791 PRIVATE StateRet_t getOption(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
792 {
793     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
794     LabelOptions_t * me = pCSLabel->pCurrentLabelOptions;
795     if (!token)
796         return StateRet_WARN_NO_MATCH;
797     if (!me)
798         me = pCSLabel->pCurrentLabelOptions = LabelOptions_new(pCSLabel->pCurrentServiceInfo->pLabelOptions);
799     /* match token against legal options */
800     pCSParse->pParseContext->valType = ValType_NONE;  /* use valType to flag a match */
801     do { /* fake do loop for break statements (to religiously avoid the goto) */
802         CHECK_OPTION_TOKEN_DVAL1("at", &me->at)
803         CHECK_OPTION_TOKEN_SVAL1("by", &me->by, CharSet_EXT_ALPHANUM)
804         CHECK_OPTION_TOKEN_SVAL1("complete_label", &me->complete_label, CharSet_URL)
805         CHECK_OPTION_TOKEN_SVAL1("full", &me->complete_label, CharSet_URL)
806         CHECK_OPTION_TOKEN_SVAL1("for", &me->fur, CharSet_URL)
807         CHECK_OPTION_TOKEN_BVAL1("generic", &me->generic)
808         CHECK_OPTION_TOKEN_BVAL1("gen", &me->generic)
809         CHECK_OPTION_TOKEN_SVAL1("MIC-md5", &me->MIC_md5, CharSet_BASE64)
810         CHECK_OPTION_TOKEN_SVAL1("md5", &me->MIC_md5, CharSet_BASE64)
811         CHECK_OPTION_TOKEN_DVAL1("on", &me->on)
812         CHECK_OPTION_TOKEN_SVAL1("signature-PKCS", &me->signature_PKCS, CharSet_BASE64)
813         CHECK_OPTION_TOKEN_DVAL1("until", &me->until)
814         CHECK_OPTION_TOKEN_DVAL1("exp", &me->until)
815 		if (!strcasecomp(token, "comment")) {
816 			pCSParse->pParseContext->valTarget.pTargetList = &me->comments;
817 		    pCSParse->pParseContext->valType = ValType_COMMENT;
818 		    break;
819 		}
820     } while (0);
821     if (pCSParse->pParseContext->valType == ValType_NONE)
822         return StateRet_WARN_NO_MATCH;
823     if (Punct_badDemark(pStateToken->validPunctuation, demark))
824         return StateRet_WARN_BAD_PUNCT;
825     return StateRet_OK;
826 }
827 
getOptionValue(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)828 PRIVATE StateRet_t getOptionValue(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
829 {
830     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
831 
832     switch (pCSParse->pParseContext->valType) {
833         case ValType_BVAL:
834             BVal_readVal(pCSParse->pParseContext->valTarget.pTargetBVal, token);
835             pCSParse->pParseContext->valType = ValType_NONE;
836             break;
837         case ValType_FVAL:
838             CHECK_CAR_SET(CharSet_NUMBER)
839             FVal_readVal(pCSParse->pParseContext->valTarget.pTargetFVal, token);
840             pCSParse->pParseContext->valType = ValType_NONE;
841             break;
842         case ValType_SVAL:
843             CHECK_CAR_SET(pCSLabel->targetCharSet)
844             SVal_readVal(pCSParse->pParseContext->valTarget.pTargetSVal, token);
845             pCSParse->pParseContext->valType = ValType_NONE;
846             break;
847         case ValType_DVAL:
848             CHECK_CAR_SET(CharSet_DATE)
849             DVal_readVal(pCSParse->pParseContext->valTarget.pTargetDVal, token);
850             pCSParse->pParseContext->valType = ValType_NONE;
851             break;
852         case ValType_COMMENT:
853             CHECK_CAR_SET(CharSet_EXT_ALPHANUM)
854 			{
855 				char * ptr = 0;
856 				StrAllocCopy(ptr, token);
857 				HTList_appendObject(*pCSParse->pParseContext->valTarget.pTargetList, (void *)ptr);
858 			}
859             break;
860 	default:
861 	    break;
862     }
863     return StateRet_OK;
864 }
865 
LabelList_open(CSParse_t * pCSParse,char * token,char demark)866 PRIVATE StateRet_t LabelList_open(CSParse_t * pCSParse, char * token, char demark)
867 {
868     return StateRet_OK;
869 }
870 
LabelList_getVersion(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)871 PRIVATE StateRet_t LabelList_getVersion(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
872 {
873 static const char versionPrefix[] = "PICS-";
874     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
875 
876     if (!token)
877         return StateRet_WARN_NO_MATCH;
878     if (strncasecomp(token, versionPrefix, sizeof(versionPrefix)-1))
879         return StateRet_WARN_NO_MATCH;
880 	token += sizeof(versionPrefix)-1;
881     CHECK_CAR_SET(CharSet_NUMBER)
882     FVal_readVal(&pCSLabel->pCSLLData->version, token);
883     return StateRet_OK;
884 }
885 
LabelList_close(CSParse_t * pCSParse,char * token,char demark)886 PRIVATE StateRet_t LabelList_close(CSParse_t * pCSParse, char * token, char demark)
887 {
888     return StateRet_DONE;
889 }
890 
LabelList_destroy(CSParse_t * pCSParse)891 PRIVATE void LabelList_destroy(CSParse_t * pCSParse)
892 {
893 }
894 
ServiceInfo_open(CSParse_t * pCSParse,char * token,char demark)895 PRIVATE StateRet_t ServiceInfo_open(CSParse_t * pCSParse, char * token, char demark)
896 {
897     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
898 
899     pCSLabel->pCurrentServiceInfo = ServiceInfo_new();
900     pCSLabel->currentLabelNumber = 0;
901     HTList_appendObject(pCSLabel->pCSLLData->serviceInfos, (void *)pCSLabel->pCurrentServiceInfo);
902     pCSLabel->pCurrentLabelOptions = pCSLabel->pCurrentServiceInfo->pLabelOptions;
903 	return StateRet_OK;
904 }
905 
ServiceInfo_getServiceId(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)906 PRIVATE StateRet_t ServiceInfo_getServiceId(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
907 {
908     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
909     ParseContext_t * pParseContext = pCSParse->pParseContext;
910 
911     if (!token || !pParseContext->observedQuotes)
912         return StateRet_WARN_NO_MATCH;
913     if (Punct_badDemark(pStateToken->validPunctuation, demark))
914         return StateRet_WARN_BAD_PUNCT;
915     CHECK_CAR_SET(CharSet_URL)
916     SVal_readVal(&pCSLabel->pCurrentServiceInfo->rating_service, token);
917     return StateRet_OK;
918 }
919 
ServiceInfo_close(CSParse_t * pCSParse,char * token,char demark)920 PRIVATE StateRet_t ServiceInfo_close(CSParse_t * pCSParse, char * token, char demark)
921 {
922     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
923 
924     pCSLabel->pCurrentServiceInfo = 0;
925 	return StateRet_OK;
926 }
927 
ServiceInfo_destroy(CSParse_t * pCSParse)928 PRIVATE void ServiceInfo_destroy(CSParse_t * pCSParse)
929 {
930     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
931     HTList_removeObject(pCSLabel->pCSLLData->serviceInfos, (void *)pCSLabel->pCurrentServiceInfo);
932     ServiceInfo_free(pCSLabel->pCurrentServiceInfo);
933     pCSLabel->pCurrentServiceInfo = 0;
934 }
935 
ServiceInfo_clearOpts(CSParse_t * pCSParse,char * token,char demark)936 PRIVATE StateRet_t ServiceInfo_clearOpts(CSParse_t * pCSParse, char * token, char demark)
937 {
938     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
939     pCSLabel->pCurrentLabelOptions = 0; /* needed to flag new SingleLabel started by option */
940     return StateRet_OK;
941 }
942 
Label_open(CSParse_t * pCSParse,char * token,char demark)943 PRIVATE StateRet_t Label_open(CSParse_t * pCSParse, char * token, char demark)
944 {
945     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
946 
947     pCSLabel->pCurrentLabel = Label_new();
948     pCSLabel->currentLabelNumber++;
949     HTList_appendObject(pCSLabel->pCurrentServiceInfo->labels, (void*)pCSLabel->pCurrentLabel);
950     return StateRet_OK;
951 }
952 
Label_close(CSParse_t * pCSParse,char * token,char demark)953 PRIVATE StateRet_t Label_close(CSParse_t * pCSParse, char * token, char demark)
954 {
955     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
956 
957     pCSLabel->pCurrentLabel = 0;
958     return StateRet_OK;
959 }
960 
Label_destroy(CSParse_t * pCSParse)961 PRIVATE void Label_destroy(CSParse_t * pCSParse)
962 {
963     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
964     HTList_removeObject(pCSLabel->pCurrentServiceInfo->labels, pCSLabel->pCurrentLabel);
965     Label_free(pCSLabel->pCurrentLabel);
966     pCSLabel->pCurrentLabel = 0;
967 }
968 
LabelTree_open(CSParse_t * pCSParse,char * token,char demark)969 PRIVATE StateRet_t LabelTree_open(CSParse_t * pCSParse, char * token, char demark)
970 {
971     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
972 
973     pCSLabel->pCSLLData->hasTree = 1;
974     pCSLabel->pCurrentLabelTree = pCSLabel->pCurrentLabel->singleLabels = HTList_new();
975     return StateRet_OK;
976 }
977 
LabelTree_close(CSParse_t * pCSParse,char * token,char demark)978 PRIVATE StateRet_t LabelTree_close(CSParse_t * pCSParse, char * token, char demark)
979 {
980     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
981 /*    Label_close(pCSParse, token, demark); */
982     pCSLabel->pCurrentLabelTree = 0;
983     return StateRet_OK;
984 }
985 
LabelTree_destroy(CSParse_t * pCSParse)986 PRIVATE void LabelTree_destroy(CSParse_t * pCSParse)
987 {
988     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
989     SingleLabel_t * pSingleLabel;
990     while ((pSingleLabel = (SingleLabel_t *) HTList_removeLastObject(pCSLabel->pCurrentLabel->singleLabels)))
991         SingleLabel_free(pSingleLabel);
992     HTList_delete(pCSLabel->pCurrentLabel->singleLabels);
993     pCSLabel->pCurrentLabel->singleLabels = 0;
994 }
995 
SingleLabel_open(CSParse_t * pCSParse,char * token,char demark)996 PRIVATE StateRet_t SingleLabel_open(CSParse_t * pCSParse, char * token, char demark)
997 {
998     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
999 
1000     pCSLabel->pCurrentSingleLabel = SingleLabel_new(pCSLabel->pCurrentLabelOptions, pCSLabel->pCurrentServiceInfo->pLabelOptions);
1001     if (pCSLabel->pCurrentLabel->singleLabels)
1002         HTList_appendObject(pCSLabel->pCurrentLabel->singleLabels, (void*)pCSLabel->pCurrentSingleLabel);
1003     else
1004         pCSLabel->pCurrentLabel->pSingleLabel = pCSLabel->pCurrentSingleLabel;
1005     pCSLabel->pCurrentLabelOptions = pCSLabel->pCurrentSingleLabel->pLabelOptions;
1006     return StateRet_OK;
1007 }
1008 
SingleLabel_close(CSParse_t * pCSParse,char * token,char demark)1009 PRIVATE StateRet_t SingleLabel_close(CSParse_t * pCSParse, char * token, char demark)
1010 {
1011     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1012 
1013     pCSLabel->pCurrentSingleLabel = 0;
1014     return StateRet_OK;
1015 }
1016 
SingleLabel_destroy(CSParse_t * pCSParse)1017 PRIVATE void SingleLabel_destroy(CSParse_t * pCSParse)
1018 {
1019     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1020     if (pCSLabel->pCurrentLabel->pSingleLabel)
1021         pCSLabel->pCurrentLabel->pSingleLabel = 0;
1022     else
1023         HTList_removeObject(pCSLabel->pCurrentLabel->singleLabels, (void *)pCSLabel->pCurrentSingleLabel);
1024     SingleLabel_free(pCSLabel->pCurrentSingleLabel);
1025     pCSLabel->pCurrentSingleLabel = 0;
1026 }
1027 
LabelRating_open(CSParse_t * pCSParse,char * token,char demark)1028 PRIVATE StateRet_t LabelRating_open(CSParse_t * pCSParse, char * token, char demark)
1029 {
1030     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1031 
1032     if (!pCSLabel->pCurrentSingleLabel) /* switched from label to rating on "r" rather than <option> */
1033         SingleLabel_open(pCSParse, token, demark);
1034     pCSLabel->pCurrentLabelRating = LabelRating_new();
1035     HTList_appendObject(pCSLabel->pCurrentSingleLabel->labelRatings, (void*)pCSLabel->pCurrentLabelRating);
1036     pCSLabel->pCurrentLabelOptions = 0;
1037     return StateRet_OK;
1038 }
1039 
LabelRating_getId(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)1040 PRIVATE StateRet_t LabelRating_getId(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
1041 {
1042     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1043 
1044     if (Punct_badDemark(pStateToken->validPunctuation, demark))
1045         return StateRet_WARN_BAD_PUNCT;
1046     CHECK_CAR_SET(CharSet_TRANSMIT_NAME)
1047     SVal_readVal(&pCSLabel->pCurrentLabelRating->identifier, token);
1048     return StateRet_OK;
1049 }
1050 
LabelRating_getValue(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)1051 PRIVATE StateRet_t LabelRating_getValue(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
1052 {
1053     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1054 
1055     if (Punct_badDemark(pStateToken->validPunctuation, demark))
1056         return StateRet_WARN_BAD_PUNCT;
1057     FVal_readVal(&pCSLabel->pCurrentLabelRating->value, token);
1058     return StateRet_OK;
1059 }
1060 
LabelRating_close(CSParse_t * pCSParse,char * token,char demark)1061 PRIVATE StateRet_t LabelRating_close(CSParse_t * pCSParse, char * token, char demark)
1062 {
1063     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1064 
1065     pCSLabel->pCurrentLabelRating = 0;
1066     return StateRet_OK;
1067 }
1068 
LabelRating_destroy(CSParse_t * pCSParse)1069 PRIVATE void LabelRating_destroy(CSParse_t * pCSParse)
1070 {
1071     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1072     HTList_removeObject(pCSLabel->pCurrentSingleLabel->labelRatings, (void *)pCSLabel->pCurrentLabelRating);
1073     LabelRating_free(pCSLabel->pCurrentLabelRating);
1074     pCSLabel->pCurrentLabelRating = 0;
1075 }
1076 
LabelRating_next(CSParse_t * pCSParse,char * token,char demark)1077 PRIVATE StateRet_t LabelRating_next(CSParse_t * pCSParse, char * token, char demark)
1078 {
1079     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1080 
1081     SingleLabel_doClose(pCSParse, token, demark);
1082     if (pCSLabel->pCurrentLabelTree) {
1083         SETNEXTSTATE(&LabelTree_targetObject, SubState_A);
1084     } else {
1085 	Label_doClose(pCSParse, token, demark);
1086         SETNEXTSTATE(&Awkward_targetObject, SubState_A);
1087     }
1088     return StateRet_OK;
1089 }
1090 
LabelRatingRange_open(CSParse_t * pCSParse,char * token,char demark)1091 PRIVATE StateRet_t LabelRatingRange_open(CSParse_t * pCSParse, char * token, char demark)
1092 {
1093     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1094 
1095     pCSLabel->pCurrentRange = 0;
1096     pCSLabel->pCurrentLabelRating->ranges = HTList_new();
1097     return StateRet_OK;
1098 }
1099 
LabelRatingRange_get(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)1100 PRIVATE StateRet_t LabelRatingRange_get(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
1101 {
1102     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1103     LabelRating_t * pLabelRating = pCSLabel->pCurrentLabelRating;
1104     Range_t * me;
1105     char * ptr, * backPtr;
1106     if (!token)
1107         return StateRet_WARN_NO_MATCH;
1108     if (Punct_badDemark(pStateToken->validPunctuation, demark))
1109         return StateRet_WARN_BAD_PUNCT;
1110 	if ((me = (Range_t *) HT_CALLOC(1, sizeof(Range_t))) == NULL)
1111 	    HT_OUTOFMEM("Range_t");
1112 /*    me = Range_new(); */
1113     HTList_appendObject(pLabelRating->ranges, (void *)me);
1114     backPtr = ptr = token;
1115     while (*ptr) {
1116         if (*ptr == ':') {
1117             *ptr = 0;
1118             ptr++;
1119             break;
1120         }
1121         ptr++;
1122     }
1123     FVal_readVal(&me->min, backPtr);
1124     if (*ptr)
1125         FVal_readVal(&me->max, ptr);
1126     return StateRet_OK;
1127 }
1128 
LabelRatingRange_close(CSParse_t * pCSParse,char * token,char demark)1129 PRIVATE StateRet_t LabelRatingRange_close(CSParse_t * pCSParse, char * token, char demark)
1130 {
1131     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1132 
1133     pCSLabel->pCurrentRange = 0;
1134     return StateRet_OK;
1135 }
1136 
LabelRatingRange_destroy(CSParse_t * pCSParse)1137 PRIVATE void LabelRatingRange_destroy(CSParse_t * pCSParse)
1138 {
1139 }
1140 
Awkward_open(CSParse_t * pCSParse,char * token,char demark)1141 PRIVATE StateRet_t Awkward_open(CSParse_t * pCSParse, char * token, char demark)
1142 {
1143     return StateRet_OK;
1144 }
1145 
Awkward_close(CSParse_t * pCSParse,char * token,char demark)1146 PRIVATE StateRet_t Awkward_close(CSParse_t * pCSParse, char * token, char demark)
1147 {
1148     return StateRet_OK;
1149 }
1150 
Awkward_destroy(CSParse_t * pCSParse)1151 PRIVATE void Awkward_destroy(CSParse_t * pCSParse)
1152 {
1153 }
1154 
error_open(CSParse_t * pCSParse,char * token,char demark)1155 PRIVATE StateRet_t error_open(CSParse_t * pCSParse, char * token, char demark)
1156 {
1157     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1158 
1159     pCSLabel->pCurrentLabelError = LabelError_new();
1160     if (pCSLabel->pCurrentLabel)
1161         pCSLabel->pCurrentLabel->pLabelError = pCSLabel->pCurrentLabelError;
1162     else
1163         pCSLabel->pCurrentServiceInfo->pLabelError = pCSLabel->pCurrentLabelError;
1164     return StateRet_OK;
1165 }
1166 
error_getExpl(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)1167 PRIVATE StateRet_t error_getExpl(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
1168 {
1169     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1170     ParseContext_t * pParseContext = pCSParse->pParseContext;
1171     char * explaination = 0;
1172 
1173     if (!token || !pParseContext->observedQuotes)
1174         return StateRet_WARN_NO_MATCH;
1175     if (Punct_badDemark(pStateToken->validPunctuation, demark))
1176         return StateRet_WARN_BAD_PUNCT;
1177     CHECK_CAR_SET(CharSet_EXT_ALPHANUM)
1178     StrAllocCopy(explaination, token);
1179     HTList_appendObject(pCSLabel->pCurrentLabelError->explanations, explaination);
1180     return StateRet_OK;
1181 }
1182 
error_close(CSParse_t * pCSParse,char * token,char demark)1183 PRIVATE StateRet_t error_close(CSParse_t * pCSParse, char * token, char demark)
1184 {
1185     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1186 
1187     pCSLabel->pCurrentLabelError = 0;
1188     if (pCSLabel->pCurrentLabel)
1189         pCSLabel->pCurrentLabel->pLabelError = pCSLabel->pCurrentLabelError;
1190     else
1191         pCSLabel->pCurrentServiceInfo->pLabelError = pCSLabel->pCurrentLabelError;
1192     return StateRet_OK;
1193 }
1194 
error_destroy(CSParse_t * pCSParse)1195 PRIVATE void error_destroy(CSParse_t * pCSParse)
1196 {
1197     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1198     if (pCSLabel->pCurrentLabel)
1199         pCSLabel->pCurrentLabel->pLabelError = 0;
1200     else
1201         pCSLabel->pCurrentServiceInfo->pLabelError = 0;
1202     LabelError_free(pCSLabel->pCurrentLabelError);
1203 }
1204 
Extension_open(CSParse_t * pCSParse,char * token,char demark)1205 PRIVATE StateRet_t Extension_open(CSParse_t * pCSParse, char * token, char demark)
1206 {
1207     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1208 	Extension_t * me = Extension_new();
1209 	pCSLabel->pCurrentExtension = me;
1210 	if (!pCSLabel->pCurrentLabelOptions->extensions)
1211 		pCSLabel->pCurrentLabelOptions->extensions = HTList_new();
1212 	HTList_appendObject(pCSLabel->pCurrentLabelOptions->extensions, (void *)me);
1213 	return StateRet_OK;
1214 }
1215 
Extension_mandatory(CSParse_t * pCSParse,char * token,char demark)1216 PRIVATE StateRet_t Extension_mandatory(CSParse_t * pCSParse, char * token, char demark)
1217 {
1218     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1219 	pCSLabel->pCurrentExtension->mandatory = 1;
1220 	pCSLabel->pCSLLData->mandatoryExtensions++;
1221     return StateRet_OK;
1222 }
1223 
Extension_getURL(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)1224 PRIVATE StateRet_t Extension_getURL(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
1225 {
1226     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1227     if (!token || !pCSParse->pParseContext->observedQuotes)
1228         return StateRet_WARN_NO_MATCH;
1229     if (Punct_badDemark(pStateToken->validPunctuation, demark))
1230         return StateRet_WARN_BAD_PUNCT;
1231     CHECK_CAR_SET(CharSet_URL)
1232 	SVal_readVal(&pCSLabel->pCurrentExtension->url, token);
1233 	return StateRet_OK;
1234 }
1235 
Extension_close(CSParse_t * pCSParse,char * token,char demark)1236 PRIVATE StateRet_t Extension_close(CSParse_t * pCSParse, char * token, char demark)
1237 {
1238     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1239 	pCSLabel->pCurrentExtension = 0;
1240 	return StateRet_OK;
1241 }
1242 
Extension_destroy(CSParse_t * pCSParse)1243 PRIVATE void Extension_destroy(CSParse_t * pCSParse)
1244 {
1245     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1246     HTList_removeObject(pCSLabel->pCurrentLabelOptions->extensions, (void *)pCSLabel->pCurrentExtension);
1247 	if (!HTList_count(pCSLabel->pCurrentLabelOptions->extensions)) {
1248         HTList_delete(pCSLabel->pCurrentLabelOptions->extensions);
1249         pCSLabel->pCurrentLabelOptions->extensions = 0;
1250     }
1251     Extension_free(pCSLabel->pCurrentExtension);
1252     pCSLabel->pCurrentExtension = 0;
1253 }
1254 
Extension_next(CSParse_t * pCSParse,char * token,char demark)1255 PRIVATE StateRet_t Extension_next(CSParse_t * pCSParse, char * token, char demark)
1256 {
1257     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1258     if (pCSLabel->pCurrentSingleLabel) {
1259         SETNEXTSTATE(&SingleLabel_targetObject, SubState_A);
1260     } else {
1261         SETNEXTSTATE(&ServiceInfo_targetObject, SubState_B);
1262     }
1263 	return StateRet_OK;
1264 }
1265 
ExtensionData_open(CSParse_t * pCSParse,char * token,char demark)1266 PRIVATE StateRet_t ExtensionData_open(CSParse_t * pCSParse, char * token, char demark)
1267 {
1268     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1269 	ExtensionData_t * me = ExtensionData_new();
1270 
1271 	me->pParentExtensionData = pCSLabel->pCurrentExtensionData;
1272 	if(pCSLabel->pCurrentExtensionData) {
1273 		if (!pCSLabel->pCurrentExtensionData->moreData)
1274 			pCSLabel->pCurrentExtensionData->moreData = HTList_new();
1275 		HTList_appendObject(pCSLabel->pCurrentExtensionData->moreData, (void *)me);
1276 	} else {
1277 		if (!pCSLabel->pCurrentExtension->extensionData)
1278 			pCSLabel->pCurrentExtension->extensionData = HTList_new();
1279 		HTList_appendObject(pCSLabel->pCurrentExtension->extensionData, (void *)me);
1280 	}
1281 	pCSLabel->pCurrentExtensionData = me;
1282 	return StateRet_OK;
1283 }
1284 
ExtensionData_next(CSParse_t * pCSParse,char * token,char demark)1285 PRIVATE StateRet_t ExtensionData_next(CSParse_t * pCSParse, char * token, char demark)
1286 {
1287     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1288 	/* close has already set recursed to the parentExtensionData */
1289     if (pCSLabel->pCurrentExtensionData) {
1290         SETNEXTSTATE(&ExtensionData_targetObject, SubState_B);
1291     } else {
1292         SETNEXTSTATE(&Extension_targetObject, SubState_C);
1293     }
1294     return StateRet_OK;
1295 }
1296 
ExtensionData_close(CSParse_t * pCSParse,char * token,char demark)1297 PRIVATE StateRet_t ExtensionData_close(CSParse_t * pCSParse, char * token, char demark)
1298 {
1299     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1300     pCSLabel->pCurrentExtensionData = pCSLabel->pCurrentExtensionData->pParentExtensionData;
1301     return StateRet_OK;
1302 }
1303 
ExtensionData_destroy(CSParse_t * pCSParse)1304 PRIVATE void ExtensionData_destroy(CSParse_t * pCSParse)
1305 {
1306     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1307     HTList ** pHolderList = pCSLabel->pCurrentExtensionData->pParentExtensionData ?
1308                             &pCSLabel->pCurrentExtensionData->pParentExtensionData->moreData :
1309                             &pCSLabel->pCurrentExtension->extensionData;
1310     HTList_removeObject(*pHolderList, (void *)pCSLabel->pCurrentExtensionData);
1311 	if (!HTList_count(*pHolderList)) {
1312         HTList_delete(*pHolderList);
1313         *pHolderList = 0;
1314     }
1315     ExtensionData_free(pCSLabel->pCurrentExtensionData);
1316     pCSLabel->pCurrentExtensionData = 0;
1317 }
1318 
ExtensionData_getData(CSParse_t * pCSParse,StateToken_t * pStateToken,char * token,char demark)1319 PRIVATE StateRet_t ExtensionData_getData(CSParse_t * pCSParse, StateToken_t * pStateToken, char * token, char demark)
1320 {
1321     CSLabel_t * pCSLabel = GetCSLabel(pCSParse);
1322 	ExtensionData_t * me;
1323     if (!token)
1324         return StateRet_WARN_NO_MATCH;
1325     if (Punct_badDemark(pStateToken->validPunctuation, demark))
1326         return StateRet_WARN_BAD_PUNCT;
1327     CHECK_CAR_SET(CharSet_EXT_DATA)
1328 	me = pCSLabel->pCurrentExtensionData;
1329 /*    SVal_readVal(&me->text, token); */
1330 	StrAllocCopy(me->text, token);
1331 	me->quoted = pCSParse->pParseContext->observedQuotes;
1332 	return StateRet_OK;
1333 }
1334 #if 0
1335 PRIVATE StateRet_t LabelRating_doClose(CSParse_t * pCSParse, char * token, char demark)
1336 {
1337     if (pCSParse->pParseContext->pTargetChangeCallback &&
1338 		(*pCSParse->pParseContext->pTargetChangeCallback)(pCSParse, &LabelRating_targetObject, CSLLTC_RATING, 2) == StateRet_ERROR)
1339 			return NowIn_ERROR;
1340     return LabelRating_close(pCSParse, token, demark);
1341 }
1342 #endif
SingleLabel_doClose(CSParse_t * pCSParse,char * token,char demark)1343 PRIVATE StateRet_t SingleLabel_doClose(CSParse_t * pCSParse, char * token, char demark)
1344 {
1345     if (pCSParse->pParseContext->pTargetChangeCallback &&
1346        	(*pCSParse->pParseContext->pTargetChangeCallback)(pCSParse, &SingleLabel_targetObject, CSLLTC_SINGLE, 2, 0) == StateRet_ERROR) /* !!! - pVoid */
1347 			return NowIn_ERROR;
1348 	return SingleLabel_close(pCSParse, token, demark);
1349 }
1350 #if 0
1351 PRIVATE StateRet_t LabelTree_doClose(CSParse_t * pCSParse, char * token, char demark)
1352 {
1353     if (pCSParse->pParseContext->pTargetChangeCallback &&
1354 		(*pCSParse->pParseContext->pTargetChangeCallback)(pCSParse, &LabelTree_targetObject, CSLLTC_LABTREE, 2) == StateRet_ERROR)
1355 			return NowIn_ERROR;
1356 	return LabelTree_close(pCSParse, token, demark);
1357 }
1358 #endif
Label_doClose(CSParse_t * pCSParse,char * token,char demark)1359 PRIVATE StateRet_t Label_doClose(CSParse_t * pCSParse, char * token, char demark)
1360 {
1361     if (pCSParse->pParseContext->pTargetChangeCallback &&
1362        	(*pCSParse->pParseContext->pTargetChangeCallback)(pCSParse, &Label_targetObject, CSLLTC_LABEL, 2, 0) == StateRet_ERROR) /* !!! - pVoid */
1363 			return NowIn_ERROR;
1364 	return Label_close(pCSParse, token, demark);
1365 }
1366 #if 0
1367 PRIVATE StateRet_t ServiceInfo_doClose(CSParse_t * pCSParse, char * token, char demark)
1368 {
1369     if (pCSParse->pParseContext->pTargetChangeCallback &&
1370 		(*pCSParse->pParseContext->pTargetChangeCallback)(pCSParse, &ServiceInfo_targetObject, CSLLTC_SERVICE, 2) == StateRet_ERROR)
1371 			return NowIn_ERROR;
1372     return ServiceInfo_close(pCSParse, token, demark);
1373 }
1374 #endif
1375 /* CSParse_doc end */
1376 /* I T E R A T O R S - scan through the CSLabel data structures for <identifier> */
1377 /* CSLabel_iterateServices - look for rating service in a label list
1378 	   (pCSLabel->pCurrentServiceInfo = (ServiceInfo_t *) HTList_nextObject(serviceInfos)) &&
1379 	   SVal_initialized(&pCSLabel->pCurrentServiceInfo->rating_service))
1380         if (!identifier || !strcasecomp(SVal_value(&pCSLabel->pCurrentServiceInfo->rating_service), identifier)) {
1381 	    ret = (*pIteratorCB)(pCSLabel, pParms, identifier, pVoid);
1382             count++;
1383  */
CSLabel_iterateServices(CSLabel_t * pCSLabel,CSLabel_callback_t * pIteratorCB,State_Parms_t * pParms,const char * identifier,void * pVoid)1384 PUBLIC CSError_t CSLabel_iterateServices(CSLabel_t * pCSLabel, CSLabel_callback_t * pIteratorCB, State_Parms_t * pParms, const char * identifier, void * pVoid)
1385 {
1386     HTList * serviceInfos;
1387     CSError_t ret = CSError_OK;
1388     int count = 0;
1389     if (!pIteratorCB ||
1390         !pCSLabel ||
1391         !pCSLabel->pCSLLData->serviceInfos)
1392         return CSError_BAD_PARAM;
1393     serviceInfos = pCSLabel->pCSLLData->serviceInfos;
1394     while (ret == CSError_OK &&
1395 	   (pCSLabel->pCurrentServiceInfo = (ServiceInfo_t *) HTList_nextObject(serviceInfos))) {
1396         if (identifier &&
1397 	    (!SVal_initialized(&pCSLabel->pCurrentServiceInfo->rating_service) ||
1398 	     strcasecomp(SVal_value(&pCSLabel->pCurrentServiceInfo->rating_service), identifier)))
1399 	    continue;
1400 	ret = (*pIteratorCB)(pCSLabel, pParms, identifier, pVoid);
1401 	count++;
1402     }
1403     if (!count)
1404         return CSError_SERVICE_MISSING;
1405     return ret;
1406 }
1407 
1408 /* CSLabel_iterateLabels - look through all labels in current ServiceInfo
1409  */
CSLabel_iterateLabels(CSLabel_t * pCSLabel,CSLabel_callback_t * pIteratorCB,State_Parms_t * pParms,const char * identifier,void * pVoid)1410 PUBLIC CSError_t CSLabel_iterateLabels(CSLabel_t * pCSLabel, CSLabel_callback_t * pIteratorCB, State_Parms_t * pParms, const char * identifier, void * pVoid)
1411 {
1412     HTList * labels;
1413     CSError_t ret= CSError_OK;
1414     int count = 0;
1415     if (!pIteratorCB ||
1416         !pCSLabel ||
1417         !pCSLabel->pCurrentServiceInfo ||
1418         !pCSLabel->pCurrentServiceInfo->labels)
1419         return CSError_BAD_PARAM;
1420     labels = pCSLabel->pCurrentServiceInfo->labels;
1421 	while (ret == CSError_OK && (pCSLabel->pCurrentLabel = (Label_t *) HTList_nextObject(labels))) {
1422             ret = (*pIteratorCB)(pCSLabel, pParms, identifier, pVoid);
1423             count++;
1424         }
1425     if (!count)
1426         return CSError_LABEL_MISSING;
1427     return ret;
1428 }
1429 
1430 /* CSLabel_iterateSingleLabels - look through all single labels in current label
1431  */
CSLabel_iterateSingleLabels(CSLabel_t * pCSLabel,CSLabel_callback_t * pIteratorCB,State_Parms_t * pParms,const char * identifier,void * pVoid)1432 PUBLIC CSError_t CSLabel_iterateSingleLabels(CSLabel_t * pCSLabel, CSLabel_callback_t * pIteratorCB, State_Parms_t * pParms, const char * identifier, void * pVoid)
1433 {
1434     CSError_t ret= CSError_OK;
1435     int count = 0;
1436     if (!pIteratorCB ||
1437         !pCSLabel ||
1438         !pCSLabel->pCurrentServiceInfo ||
1439         !pCSLabel->pCurrentServiceInfo->labels)
1440         return CSError_BAD_PARAM;
1441     {
1442     if (pCSLabel->pCurrentLabel->pSingleLabel) {
1443         pCSLabel->pCurrentSingleLabel = pCSLabel->pCurrentLabel->pSingleLabel;
1444             ret = (*pIteratorCB)(pCSLabel, pParms, identifier, pVoid);
1445             count++;
1446     }
1447     else {
1448         HTList * singleLabels = pCSLabel->pCurrentLabel->singleLabels;
1449     	while (ret == CSError_OK && (pCSLabel->pCurrentSingleLabel = (SingleLabel_t *) HTList_nextObject(singleLabels))) {
1450                 ret = (*pIteratorCB)(pCSLabel, pParms, identifier, pVoid);
1451                 count++;
1452             }
1453         }
1454     }
1455     if (!count)
1456         return CSError_SINGLELABEL_MISSING;
1457     return ret;
1458 }
1459 
1460 /* CSLabel_iterateLabelRatings - look for rating in current single label
1461  */
CSLabel_iterateLabelRatings(CSLabel_t * pCSLabel,CSLabel_callback_t * pIteratorCB,State_Parms_t * pParms,const char * identifier,void * pVoid)1462 PUBLIC CSError_t CSLabel_iterateLabelRatings(CSLabel_t * pCSLabel, CSLabel_callback_t * pIteratorCB, State_Parms_t * pParms, const char * identifier, void * pVoid)
1463 {
1464     HTList * labelRatings;
1465     CSError_t ret = CSError_OK;
1466     int count = 0;
1467     if (!pIteratorCB ||
1468         !pCSLabel ||
1469         !pCSLabel->pCurrentServiceInfo ||
1470         !pCSLabel->pCurrentServiceInfo->labels ||
1471         !pCSLabel->pCurrentLabel ||
1472         !pCSLabel->pCurrentSingleLabel ||
1473         !pCSLabel->pCurrentSingleLabel->labelRatings)
1474         return CSError_BAD_PARAM;
1475     labelRatings = pCSLabel->pCurrentSingleLabel->labelRatings;
1476 	while (ret == CSError_OK && (pCSLabel->pCurrentLabelRating = (LabelRating_t *) HTList_nextObject(labelRatings)))
1477         if (!identifier || !strcasecomp(SVal_value(&pCSLabel->pCurrentLabelRating->identifier), identifier)) {
1478             ret = (*pIteratorCB)(pCSLabel, pParms, identifier, pVoid);
1479             count++;
1480         }
1481     if (!count)
1482         return CSError_RATING_MISSING;
1483     return ret;
1484 }
1485 
1486 /* R A N G E   T E S T I N G - check that label values fall within acceptable user ranges */
1487 /* CSLabel_ratingsIncludeFVal - find out if current rating in pCSLabel encompases userValue
1488  * return: int stating how far it is from fitting.
1489  */
CSLabel_ratingsIncludeFVal(CSLabel_t * pCSLabel,FVal_t * userValue)1490 PUBLIC FVal_t CSLabel_ratingsIncludeFVal(CSLabel_t * pCSLabel, FVal_t * userValue)
1491 {
1492     Range_t parm = Range_NEW_UNINITIALIZED;
1493     parm.min = *userValue;
1494     return CSLabel_ratingsIncludeRange(pCSLabel, &parm);
1495 }
1496 
CSLabel_ratingsIncludeRange(CSLabel_t * pCSLabel,Range_t * pUserRange)1497 PUBLIC FVal_t CSLabel_ratingsIncludeRange(CSLabel_t * pCSLabel, Range_t * pUserRange)
1498 {
1499     HTList * labelRanges = pCSLabel->pCurrentLabelRating->ranges;
1500     FVal_t value = pCSLabel->pCurrentLabelRating->value;
1501     FVal_t ret;
1502     Range_t * pLabelRange;
1503     if (FVal_initialized(&value)) {
1504         Range_t parm = Range_NEW_UNINITIALIZED;
1505         parm.min = value;
1506         return Range_gap(&parm, pUserRange);
1507     }
1508     while ((pLabelRange = (Range_t *)HTList_nextObject(labelRanges))) {
1509         FVal_t thisOne = Range_gap(pLabelRange, pUserRange);
1510         if (FVal_isZero(&thisOne))
1511             return thisOne;
1512         if (FVal_nearerZero(&thisOne, &ret))
1513             ret = thisOne;
1514     }
1515     return ret;
1516 }
1517 
CSLabel_ratingsIncludeRanges(CSLabel_t * pCSLabel,HTList * userRanges)1518 PUBLIC FVal_t CSLabel_ratingsIncludeRanges(CSLabel_t * pCSLabel, HTList * userRanges)
1519 {
1520     FVal_t ret;
1521     Range_t * pUserRange;
1522     BOOL retInitialized = NO;
1523     while ((pUserRange = (Range_t *)HTList_nextObject(userRanges))) {
1524         FVal_t thisOne = CSLabel_ratingsIncludeRange(pCSLabel, pUserRange);
1525         if (FVal_isZero(&thisOne))
1526             return thisOne;
1527 	if (retInitialized) {
1528 	    if (FVal_nearerZero(&thisOne, &ret))
1529 	        ret = thisOne;
1530 	} else {
1531 	    ret = thisOne;
1532 	    retInitialized = YES;
1533 	}
1534     }
1535     return ret;
1536 }
1537 
1538