CQL w/bison on WIN32
[yaz-moved-to-github.git] / zutil / srw.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.5 2003-02-18 14:28:53 adam Exp $
6  */
7
8 #include <yaz/srw.h>
9
10 #if HAVE_XML2
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
13
14 static void add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
15                              int len)
16 {
17     if (val)
18     {
19         xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
20         xmlNodePtr t = xmlNewTextLen(val, len);
21         xmlAddChild(c, t);
22     }
23 }
24
25 static void add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
26 {
27     if (val)
28         xmlNewChild(ptr, 0, elem, val);
29 }
30
31 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
32 {
33     if (val)
34     {
35         char str[30];
36         sprintf(str, "%d", *val);
37         xmlNewChild(ptr, 0, elem, str);
38     }
39 }
40
41 static int match_element(xmlNodePtr ptr, const char *elem)
42 {
43     if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
44         return 1;
45     return 0;
46 }
47
48 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
49                               char **val, int *len)
50 {
51     struct _xmlAttr *attr;
52     if (!match_element(ptr, elem))
53         return 0;
54 #if 0
55     for (attr = ptr->properties; attr; attr = attr->next)
56         if (!strcmp(attr->name, "type") &&
57             attr->children && attr->children->type == XML_TEXT_NODE)
58         {
59             const char *t = strchr(attr->children->content, ':');
60             if (t)
61                 t = t + 1;
62             else
63                 t = attr->children->content;
64             if (!strcmp(t, "string"))
65                 break;
66         }
67     if (!attr)
68         return 0;
69 #endif
70     ptr = ptr->children;
71     if (!ptr || ptr->type != XML_TEXT_NODE)
72         return 0;
73     *val = odr_strdup(o, ptr->content);
74     if (len)
75         *len = strlen(ptr->content);
76     return 1;
77 }
78
79
80 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
81                             char **val)
82 {
83     return match_xsd_string_n(ptr, elem, o, val, 0);
84 }
85                      
86 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
87 {
88     struct _xmlAttr *attr;
89     if (!match_element(ptr, elem))
90         return 0;
91 #if 0
92     for (attr = ptr->properties; attr; attr = attr->next)
93         if (!strcmp(attr->name, "type") &&
94             attr->children && attr->children->type == XML_TEXT_NODE)
95         {
96             const char *t = strchr(attr->children->content, ':');
97             if (t)
98                 t = t + 1;
99             else
100                 t = attr->children->content;
101             if (!strcmp(t, "integer"))
102                 break;
103         }
104     if (!attr)
105         return 0;
106 #endif
107     ptr = ptr->children;
108     if (!ptr || ptr->type != XML_TEXT_NODE)
109         return 0;
110     *val = odr_intdup(o, atoi(ptr->content));
111     return 1;
112 }
113
114 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
115                            int *num, void *client_data, const char *ns)
116 {
117     if (o->direction == ODR_DECODE)
118     {
119         int i;
120         xmlNodePtr ptr;
121         *num = 0;
122         for (ptr = pptr->children; ptr; ptr = ptr->next)
123         {
124             if (ptr->type == XML_ELEMENT_NODE &&
125                 !strcmp(ptr->name, "record"))
126                 (*num)++;
127         }
128         if (!*num)
129             return 1;
130         *recs = odr_malloc(o, *num * sizeof(**recs));
131         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
132         {
133             if (ptr->type == XML_ELEMENT_NODE &&
134                 !strcmp(ptr->name, "record"))
135             {
136                 xmlNodePtr rptr;
137                 (*recs)[i].recordSchema = 0;
138                 (*recs)[i].recordData_buf = 0;
139                 (*recs)[i].recordData_len = 0;
140                 (*recs)[i].recordPosition = 0;
141                 for (rptr = ptr->children; rptr; rptr = rptr->next)
142                 {
143                     if (match_xsd_string(rptr, "recordSchema", o, 
144                                          &(*recs)[i].recordSchema))
145                         ;
146                     else if (match_xsd_string_n(rptr, "recordData", o, 
147                                                 &(*recs)[i].recordData_buf,
148                                                 &(*recs)[i].recordData_len))
149                         ;
150                     else if (match_xsd_integer(rptr, "recordPosition", o, 
151                                                &(*recs)[i].recordPosition))
152                         ;
153                 }
154             }
155         }
156     }
157     else if (o->direction == ODR_ENCODE)
158     {
159         int i;
160         for (i = 0; i < *num; i++)
161         {
162             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
163             add_xsd_string(rptr, "recordSchema", (*recs)[i].recordSchema);
164             add_xsd_string_n(rptr, "recordData", (*recs)[i].recordData_buf,
165                              (*recs)[i].recordData_len);
166             add_xsd_integer(rptr, "recordPosition", (*recs)[i].recordPosition);
167         }
168     }
169     return 0;
170 }
171
172 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
173                                int *num, void *client_data, const char *ns)
174 {
175     if (o->direction == ODR_DECODE)
176     {
177         int i;
178         xmlNodePtr ptr;
179         *num = 0;
180         for (ptr = pptr->children; ptr; ptr = ptr->next)
181         {
182             if (ptr->type == XML_ELEMENT_NODE &&
183                 !strcmp(ptr->name, "diagnostic"))
184                 (*num)++;
185         }
186         if (!*num)
187             return 1;
188         *recs = odr_malloc(o, *num * sizeof(**recs));
189         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
190         {
191             if (ptr->type == XML_ELEMENT_NODE &&
192                 !strcmp(ptr->name, "diagnostic"))
193             {
194                 xmlNodePtr rptr;
195                 (*recs)[i].code = 0;
196                 (*recs)[i].details = 0;
197                 for (rptr = ptr->children; rptr; rptr = rptr->next)
198                 {
199                     if (match_xsd_integer(rptr, "code", o, 
200                                                &(*recs)[i].code))
201                         ;
202                     else if (match_xsd_string(rptr, "details", o, 
203                                               &(*recs)[i].details))
204                         ;
205                 }
206                 i++;
207             }
208         }
209     }
210     else if (o->direction == ODR_ENCODE)
211     {
212         int i;
213         for (i = 0; i < *num; i++)
214         {
215             xmlNodePtr rptr = xmlNewChild(pptr, 0, "diagnostic", 0);
216             add_xsd_integer(rptr, "code", (*recs)[i].code);
217             add_xsd_string(rptr, "details", (*recs)[i].details);
218         }
219     }
220     return 0;
221 }
222
223
224 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_searchRetrieve **handler_data,
225                   void *client_data, const char *ns)
226 {
227     xmlNodePtr pptr = vptr;
228     if (o->direction == ODR_DECODE)
229     {
230         xmlNodePtr method = pptr->children;
231
232         while (method && method->type == XML_TEXT_NODE)
233             method = method->next;
234         
235         if (method->type != XML_ELEMENT_NODE)
236             return -1;
237         if (method && !strcmp(method->name, "searchRetrieveRequest"))
238         {
239             Z_SRW_searchRetrieve **p = handler_data;
240             xmlNodePtr ptr = method->children;
241             Z_SRW_searchRetrieveRequest *req;
242
243             *p = odr_malloc(o, sizeof(**p));
244             (*p)->which = Z_SRW_searchRetrieve_request;
245             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
246             req->query = 0;
247             req->xQuery = 0;
248             req->sortKeys = 0;
249             req->xSortKeys = 0;
250             req->startRecord = 0;
251             req->maximumRecords = 0;
252             req->recordSchema = 0;
253             req->recordPacking = 0;
254             req->database = 0;
255
256             for (; ptr; ptr = ptr->next)
257             {
258                 if (match_xsd_string(ptr, "query", o, 
259                                      &req->query))
260                     ;
261                 else if (match_xsd_string(ptr, "pQuery", o, 
262                                      &req->pQuery))
263                     ;
264                 else if (match_xsd_string(ptr, "sortKeys", o, 
265                                           &req->sortKeys))
266                     ;
267                 else if (match_xsd_string(ptr, "recordSchema", o, 
268                                           &req->recordSchema))
269                     ;
270                 else if (match_xsd_string(ptr, "recordPacking", o,
271                                           &req->recordPacking))
272                     ;
273                 else if (match_xsd_integer(ptr, "startRecord", o,
274                                            &req->startRecord))
275                     ;
276                 else if (match_xsd_integer(ptr, "maximumRecords", o,
277                                            &req->maximumRecords))
278                     ;
279                 else if (match_xsd_string(ptr, "database", o,
280                                            &req->database))
281                     ;
282                 /* missing is xQuery, xSortKeys .. */
283             }
284         }
285         else if (method && !strcmp(method->name, "searchRetrieveResponse"))
286         {
287             Z_SRW_searchRetrieve **p = handler_data;
288             xmlNodePtr ptr = method->children;
289             Z_SRW_searchRetrieveResponse *res;
290
291             *p = odr_malloc(o, sizeof(**p));
292             (*p)->which = Z_SRW_searchRetrieve_response;
293             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
294
295             res->numberOfRecords = 0;
296             res->resultSetId = 0;
297             res->resultSetIdleTime = 0;
298             res->records = 0;
299             res->num_records = 0;
300             res->diagnostics = 0;
301             res->num_diagnostics = 0;
302             res->nextRecordPosition = 0;
303
304             for (; ptr; ptr = ptr->next)
305             {
306                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
307                                       &res->numberOfRecords))
308                     ;
309                 else if (match_xsd_string(ptr, "resultSetId", o, 
310                                           &res->resultSetId))
311                     ;
312                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
313                                            &res->resultSetIdleTime))
314                     ;
315                 else if (match_element(ptr, "records"))
316                     yaz_srw_records(o, ptr, &res->records,
317                                     &res->num_records, client_data,
318                                     ns);
319                 else if (match_element(ptr, "diagnostics"))
320                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
321                                         &res->num_diagnostics,
322                                         client_data, ns);
323                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
324                                            &res->nextRecordPosition))
325                     ;
326             }
327
328         }
329         else
330             return -1;
331
332     }
333     else if (o->direction == ODR_ENCODE)
334     {
335         Z_SRW_searchRetrieve **p = handler_data;
336         if ((*p)->which == Z_SRW_searchRetrieve_request)
337         {
338             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
339             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
340             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
341                                          "searchRetrieveRequest", 0);
342
343             add_xsd_string(ptr, "query", req->query);
344             add_xsd_string(ptr, "pQuery", req->pQuery);
345             add_xsd_string(ptr, "sortKeys", req->sortKeys);
346             add_xsd_integer(ptr, "startRecord", req->startRecord);
347             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
348             add_xsd_string(ptr, "recordSchema", req->recordSchema);
349             add_xsd_string(ptr, "recordPacking", req->recordPacking);
350             add_xsd_string(ptr, "database", req->database);
351         }
352         else if ((*p)->which == Z_SRW_searchRetrieve_response)
353         {
354             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
355             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
356             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
357                                          "searchRetrieveResponse", 0);
358
359             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
360             add_xsd_string(ptr, "resultSetId", res->resultSetId);
361             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
362             if (res->num_records)
363             {
364                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
365                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
366                                 client_data, ns);
367             }
368             if (res->num_diagnostics)
369             {
370                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
371                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
372                                     &res->num_diagnostics, client_data, ns);
373             }
374             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
375         }
376         else
377             return -1;
378
379     }
380     return 0;
381 }
382
383 Z_SRW_searchRetrieve *yaz_srw_get(ODR o, int which)
384 {
385     Z_SRW_searchRetrieve *sr = odr_malloc(o, sizeof(*o));
386     sr->which = which;
387     switch(which)
388     {
389     case Z_SRW_searchRetrieve_request:
390         sr->u.request = odr_malloc(o, sizeof(*sr->u.request));
391         sr->u.request->query = 0;
392         sr->u.request->xQuery = 0;
393         sr->u.request->pQuery = 0;
394         sr->u.request->sortKeys = 0;
395         sr->u.request->xSortKeys = 0;
396         sr->u.request->startRecord = 0;
397         sr->u.request->maximumRecords = 0;
398         sr->u.request->recordSchema = 0;
399         sr->u.request->recordPacking = 0;
400         sr->u.request->database = 0;
401         break;
402     case Z_SRW_searchRetrieve_response:
403         sr->u.response = odr_malloc(o, sizeof(*sr->u.response));
404         sr->u.response->numberOfRecords = 0;
405         sr->u.response->resultSetId = 0;
406         sr->u.response->resultSetIdleTime = 0;
407         sr->u.response->records = 0;
408         sr->u.response->num_records = 0;
409         sr->u.response->diagnostics = 0;
410         sr->u.response->num_diagnostics = 0;
411         sr->u.response->nextRecordPosition = 0;
412     }
413     return sr;
414 }
415
416 #endif
417
418
419 static struct {
420     int code;
421     const char *msg;
422 } yaz_srw_codes [] = {
423 {1, "Permanent system error"}, 
424 {2, "System temporarily unavailable"}, 
425 {3, "Authentication error"}, 
426 /* Diagnostics Relating to CQL */
427 {10, "Illegal query"}, 
428 {11, "Unsupported query type (XCQL vs CQL)"}, 
429 {12, "Too many characters in query"}, 
430 {13, "Unbalanced or illegal use of parentheses"}, 
431 {14, "Unbalanced or illegal use of quotes"}, 
432 {15, "Illegal or unsupported index set"}, 
433 {16, "Illegal or unsupported index"}, 
434 {17, "Illegal or unsupported combination of index and index set"}, 
435 {18, "Illegal or unsupported combination of indexes"}, 
436 {19, "Illegal or unsupported relation"}, 
437 {20, "Illegal or unsupported relation modifier"}, 
438 {21, "Illegal or unsupported combination of relation modifers"}, 
439 {22, "Illegal or unsupported combination of relation and index"}, 
440 {23, "Too many characters in term"}, 
441 {24, "Illegal combination of relation and term"}, 
442 {25, "Special characters not quoted in term"}, 
443 {26, "Non special character escaped in term"}, 
444 {27, "Empty term unsupported"}, 
445 {28, "Masking character not supported"}, 
446 {29, "Masked words too short"}, 
447 {30, "Too many masking characters in term"}, 
448 {31, "Anchoring character not supported"}, 
449 {32, "Anchoring character in illegal or unsupported position"}, 
450 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
451 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
452 {35, "Terms only exclusion (stop) words"}, 
453 {36, "Term in invalid format for index or relation"}, 
454 {37, "Illegal or unsupported boolean operator"}, 
455 {38, "Too many boolean operators in query"}, 
456 {39, "Proximity not supported"}, 
457 {40, "Illegal or unsupported proximity relation"}, 
458 {41, "Illegal or unsupported proximity distance"}, 
459 {42, "Illegal or unsupported proximity unit"}, 
460 {43, "Illegal or unsupported proximity ordering"}, 
461 {44, "Illegal or unsupported combination of proximity modifiers"}, 
462 {45, "Index set name (prefix) assigned to multiple identifiers"}, 
463 /* Diagnostics Relating to Result Sets */
464 {50, "Result sets not supported"}, 
465 {51, "Result set does not exist"}, 
466 {52, "Result set temporarily unavailable"}, 
467 {53, "Result sets only supported for retrieval"}, 
468 {54, "Retrieval may only occur from an existing result set"}, 
469 {55, "Combination of result sets with search terms not supported"}, 
470 {56, "Only combination of single result set with search terms supported"}, 
471 {57, "Result set created but no records available"}, 
472 {58, "Result set created with unpredictable partial results available"}, 
473 {59, "Result set created with valid partial results available"}, 
474 /* Diagnostics Relating to Records */
475 {60, "Too many records retrieved"}, 
476 {61, "First record position out of range"}, 
477 {62, "Negative number of records requested"}, 
478 {63, "System error in retrieving records"}, 
479 {64, "Record temporarily unavailable"}, 
480 {65, "Record does not exist"}, 
481 {66, "Unknown schema for retrieval"}, 
482 {67, "Record not available in this schema"}, 
483 {68, "Not authorised to send record"}, 
484 {69, "Not authorised to send record in this schema"}, 
485 {70, "Record too large to send"}, 
486 /* Diagnostics Relating to Sorting */
487 {80, "Sort not supported"}, 
488 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
489 {82, "Illegal or unsupported sort sequence"}, 
490 {83, "Too many records"}, 
491 {84, "Too many sort keys"}, 
492 {85, "Duplicate sort keys"}, 
493 {86, "Incompatible record formats"}, 
494 {87, "Unsupported schema for sort"}, 
495 {88, "Unsupported tag path for sort"}, 
496 {89, "Tag path illegal or unsupported for schema"}, 
497 {90, "Illegal or unsupported direction value"}, 
498 {91, "Illegal or unsupported case value"}, 
499 {92, "Illegal or unsupported missing value action"}, 
500 /* Diagnostics Relating to Explain */
501 {100, "Explain not supported"}, 
502 {101, "Explain request type not supported (SOAP vs GET)"}, 
503 {102, "Explain record temporarily unavailable"},
504 {0, 0}
505 };
506
507 const char *yaz_srw_error_str (int code)
508 {
509     int i;
510     for (i = 0; yaz_srw_codes[i].code; i++)
511         if (yaz_srw_codes[i].code == code)
512             return yaz_srw_codes[i].msg;
513     return 0;
514 }
515