ODR print for HTTP packages
[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.6 2003-02-19 15:22:11 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->pQuery = 0;
248             req->xQuery = 0;
249             req->sortKeys = 0;
250             req->xSortKeys = 0;
251             req->startRecord = 0;
252             req->maximumRecords = 0;
253             req->recordSchema = 0;
254             req->recordPacking = 0;
255             req->database = 0;
256
257             for (; ptr; ptr = ptr->next)
258             {
259                 if (match_xsd_string(ptr, "query", o, 
260                                      &req->query))
261                     ;
262                 else if (match_xsd_string(ptr, "pQuery", o, 
263                                      &req->pQuery))
264                     ;
265                 else if (match_xsd_string(ptr, "sortKeys", o, 
266                                           &req->sortKeys))
267                     ;
268                 else if (match_xsd_string(ptr, "recordSchema", o, 
269                                           &req->recordSchema))
270                     ;
271                 else if (match_xsd_string(ptr, "recordPacking", o,
272                                           &req->recordPacking))
273                     ;
274                 else if (match_xsd_integer(ptr, "startRecord", o,
275                                            &req->startRecord))
276                     ;
277                 else if (match_xsd_integer(ptr, "maximumRecords", o,
278                                            &req->maximumRecords))
279                     ;
280                 else if (match_xsd_string(ptr, "database", o,
281                                            &req->database))
282                     ;
283                 /* missing is xQuery, xSortKeys .. */
284             }
285         }
286         else if (method && !strcmp(method->name, "searchRetrieveResponse"))
287         {
288             Z_SRW_searchRetrieve **p = handler_data;
289             xmlNodePtr ptr = method->children;
290             Z_SRW_searchRetrieveResponse *res;
291
292             *p = odr_malloc(o, sizeof(**p));
293             (*p)->which = Z_SRW_searchRetrieve_response;
294             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
295
296             res->numberOfRecords = 0;
297             res->resultSetId = 0;
298             res->resultSetIdleTime = 0;
299             res->records = 0;
300             res->num_records = 0;
301             res->diagnostics = 0;
302             res->num_diagnostics = 0;
303             res->nextRecordPosition = 0;
304
305             for (; ptr; ptr = ptr->next)
306             {
307                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
308                                       &res->numberOfRecords))
309                     ;
310                 else if (match_xsd_string(ptr, "resultSetId", o, 
311                                           &res->resultSetId))
312                     ;
313                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
314                                            &res->resultSetIdleTime))
315                     ;
316                 else if (match_element(ptr, "records"))
317                     yaz_srw_records(o, ptr, &res->records,
318                                     &res->num_records, client_data,
319                                     ns);
320                 else if (match_element(ptr, "diagnostics"))
321                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
322                                         &res->num_diagnostics,
323                                         client_data, ns);
324                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
325                                            &res->nextRecordPosition))
326                     ;
327             }
328
329         }
330         else
331             return -1;
332
333     }
334     else if (o->direction == ODR_ENCODE)
335     {
336         Z_SRW_searchRetrieve **p = handler_data;
337         if ((*p)->which == Z_SRW_searchRetrieve_request)
338         {
339             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
340             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
341             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
342                                          "searchRetrieveRequest", 0);
343
344             add_xsd_string(ptr, "query", req->query);
345             add_xsd_string(ptr, "pQuery", req->pQuery);
346             add_xsd_string(ptr, "sortKeys", req->sortKeys);
347             add_xsd_integer(ptr, "startRecord", req->startRecord);
348             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
349             add_xsd_string(ptr, "recordSchema", req->recordSchema);
350             add_xsd_string(ptr, "recordPacking", req->recordPacking);
351             add_xsd_string(ptr, "database", req->database);
352         }
353         else if ((*p)->which == Z_SRW_searchRetrieve_response)
354         {
355             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
356             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
357             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
358                                          "searchRetrieveResponse", 0);
359
360             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
361             add_xsd_string(ptr, "resultSetId", res->resultSetId);
362             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
363             if (res->num_records)
364             {
365                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
366                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
367                                 client_data, ns);
368             }
369             if (res->num_diagnostics)
370             {
371                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
372                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
373                                     &res->num_diagnostics, client_data, ns);
374             }
375             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
376         }
377         else
378             return -1;
379
380     }
381     return 0;
382 }
383
384 Z_SRW_searchRetrieve *yaz_srw_get(ODR o, int which)
385 {
386     Z_SRW_searchRetrieve *sr = odr_malloc(o, sizeof(*o));
387     sr->which = which;
388     switch(which)
389     {
390     case Z_SRW_searchRetrieve_request:
391         sr->u.request = odr_malloc(o, sizeof(*sr->u.request));
392         sr->u.request->query = 0;
393         sr->u.request->xQuery = 0;
394         sr->u.request->pQuery = 0;
395         sr->u.request->sortKeys = 0;
396         sr->u.request->xSortKeys = 0;
397         sr->u.request->startRecord = 0;
398         sr->u.request->maximumRecords = 0;
399         sr->u.request->recordSchema = 0;
400         sr->u.request->recordPacking = 0;
401         sr->u.request->database = 0;
402         break;
403     case Z_SRW_searchRetrieve_response:
404         sr->u.response = odr_malloc(o, sizeof(*sr->u.response));
405         sr->u.response->numberOfRecords = 0;
406         sr->u.response->resultSetId = 0;
407         sr->u.response->resultSetIdleTime = 0;
408         sr->u.response->records = 0;
409         sr->u.response->num_records = 0;
410         sr->u.response->diagnostics = 0;
411         sr->u.response->num_diagnostics = 0;
412         sr->u.response->nextRecordPosition = 0;
413     }
414     return sr;
415 }
416
417 #endif
418
419
420 static struct {
421     int code;
422     const char *msg;
423 } yaz_srw_codes [] = {
424 {1, "Permanent system error"}, 
425 {2, "System temporarily unavailable"}, 
426 {3, "Authentication error"}, 
427 /* Diagnostics Relating to CQL */
428 {10, "Illegal query"}, 
429 {11, "Unsupported query type (XCQL vs CQL)"}, 
430 {12, "Too many characters in query"}, 
431 {13, "Unbalanced or illegal use of parentheses"}, 
432 {14, "Unbalanced or illegal use of quotes"}, 
433 {15, "Illegal or unsupported index set"}, 
434 {16, "Illegal or unsupported index"}, 
435 {17, "Illegal or unsupported combination of index and index set"}, 
436 {18, "Illegal or unsupported combination of indexes"}, 
437 {19, "Illegal or unsupported relation"}, 
438 {20, "Illegal or unsupported relation modifier"}, 
439 {21, "Illegal or unsupported combination of relation modifers"}, 
440 {22, "Illegal or unsupported combination of relation and index"}, 
441 {23, "Too many characters in term"}, 
442 {24, "Illegal combination of relation and term"}, 
443 {25, "Special characters not quoted in term"}, 
444 {26, "Non special character escaped in term"}, 
445 {27, "Empty term unsupported"}, 
446 {28, "Masking character not supported"}, 
447 {29, "Masked words too short"}, 
448 {30, "Too many masking characters in term"}, 
449 {31, "Anchoring character not supported"}, 
450 {32, "Anchoring character in illegal or unsupported position"}, 
451 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
452 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
453 {35, "Terms only exclusion (stop) words"}, 
454 {36, "Term in invalid format for index or relation"}, 
455 {37, "Illegal or unsupported boolean operator"}, 
456 {38, "Too many boolean operators in query"}, 
457 {39, "Proximity not supported"}, 
458 {40, "Illegal or unsupported proximity relation"}, 
459 {41, "Illegal or unsupported proximity distance"}, 
460 {42, "Illegal or unsupported proximity unit"}, 
461 {43, "Illegal or unsupported proximity ordering"}, 
462 {44, "Illegal or unsupported combination of proximity modifiers"}, 
463 {45, "Index set name (prefix) assigned to multiple identifiers"}, 
464 /* Diagnostics Relating to Result Sets */
465 {50, "Result sets not supported"}, 
466 {51, "Result set does not exist"}, 
467 {52, "Result set temporarily unavailable"}, 
468 {53, "Result sets only supported for retrieval"}, 
469 {54, "Retrieval may only occur from an existing result set"}, 
470 {55, "Combination of result sets with search terms not supported"}, 
471 {56, "Only combination of single result set with search terms supported"}, 
472 {57, "Result set created but no records available"}, 
473 {58, "Result set created with unpredictable partial results available"}, 
474 {59, "Result set created with valid partial results available"}, 
475 /* Diagnostics Relating to Records */
476 {60, "Too many records retrieved"}, 
477 {61, "First record position out of range"}, 
478 {62, "Negative number of records requested"}, 
479 {63, "System error in retrieving records"}, 
480 {64, "Record temporarily unavailable"}, 
481 {65, "Record does not exist"}, 
482 {66, "Unknown schema for retrieval"}, 
483 {67, "Record not available in this schema"}, 
484 {68, "Not authorised to send record"}, 
485 {69, "Not authorised to send record in this schema"}, 
486 {70, "Record too large to send"}, 
487 /* Diagnostics Relating to Sorting */
488 {80, "Sort not supported"}, 
489 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
490 {82, "Illegal or unsupported sort sequence"}, 
491 {83, "Too many records"}, 
492 {84, "Too many sort keys"}, 
493 {85, "Duplicate sort keys"}, 
494 {86, "Incompatible record formats"}, 
495 {87, "Unsupported schema for sort"}, 
496 {88, "Unsupported tag path for sort"}, 
497 {89, "Tag path illegal or unsupported for schema"}, 
498 {90, "Illegal or unsupported direction value"}, 
499 {91, "Illegal or unsupported case value"}, 
500 {92, "Illegal or unsupported missing value action"}, 
501 /* Diagnostics Relating to Explain */
502 {100, "Explain not supported"}, 
503 {101, "Explain request type not supported (SOAP vs GET)"}, 
504 {102, "Explain record temporarily unavailable"},
505 {0, 0}
506 };
507
508 const char *yaz_diag_srw_str (int code)
509 {
510     int i;
511     for (i = 0; yaz_srw_codes[i].code; i++)
512         if (yaz_srw_codes[i].code == code)
513             return yaz_srw_codes[i].msg;
514     return 0;
515 }
516
517
518 /* bib1:srw */
519 static int srw_bib1_map[] = {
520     1, 1,
521     2, 2,
522     3, 11,
523     4, 35,
524     5, 12,
525     6, 38,
526     7, 30,
527     8, 32,
528     9, 29,
529     10, 10,
530     11, 12,
531     11, 23,
532     12, 60,
533     13, 61,
534     13, 62,
535     14, 63,
536     14, 64,
537     14, 65,
538     15, 68,
539     15, 69,
540     16, 70,
541     17, 70,
542     18, 50,
543     19, 55,
544     20, 56, 
545     21, 52,
546     22, 50,
547     23, 1,  /* bad map */
548     24, 63, /* bad map */
549     25, 63, /* bad map */
550     26, 63, /* bad map */
551     27, 51,
552     28, 52,
553     29, 52,
554     30, 51,
555     31, 57,
556     32, 58,
557     33, 59,
558     100, 1, /* bad map */
559     101, 3,
560     102, 3,
561     103, 3,
562     104, 3,
563     105, 3, 
564     106, 66,
565     107, 11,
566     108, 10,
567     108, 13,
568     108, 14,
569     108, 25,
570     108, 26,
571     108, 27,
572     108, 45,
573         
574     109, 1,
575     110, 37,
576     111, 1,
577     112, 58,
578     113, 10,
579     114, 16,
580     115, 16,
581     116, 16,
582     117, 19,
583     118, 22,
584     119, 32,
585     119, 31,
586     120, 28,
587     121, 15,
588     122, 32,
589     123, 22,
590     123, 17,
591     123, 18,
592     124, 24,
593     125, 36,
594     126, 36, 
595     127, 36,
596     128, 51,
597     129, 39,
598     130, 43,
599     131, 40,
600     132, 42,
601     201, 44,
602     201, 33,
603     201, 34,
604     202, 41,
605     203, 43,
606     205, 1,  /* bad map */
607     206, 1,  /* bad map */
608     207, 89,
609     208, 1,  /* bad map */
610     209, 80,
611     210, 80,
612     210, 81,
613     211, 84,
614     212, 85,
615     213, 92,
616     214, 90,
617     215, 91,
618     216, 92,
619     217, 63,
620     218, 1,  /* bad map */
621     219, 1,  /* bad map */
622     220, 1,  /* bad map */
623     221, 1,  /* bad map */
624     222, 1,  /* bad map */
625     223, 1,  /* bad map */
626     224, 1,  /* bad map */
627     225, 1,  /* bad map */
628     226, 1,  /* bad map */
629     227, 66,
630     228, 1,  /* bad map */
631     229, 36,
632     230, 83,
633     231, 89,
634     232, 1,
635     233, 1, /* bad map */
636     234, 1, /* bad map */
637     235, 2,
638     236, 3, 
639     237, 82,
640     238, 67,
641     239, 66,
642     240, 1, /* bad map */
643     241, 1, /* bad map */
644     242, 70,
645     243, 1, /* bad map */
646     244, 66,
647     245, 10,
648     246, 10,
649     247, 10,
650     1001, 1, /* bad map */
651     1002, 1, /* bad map */
652     1003, 1, /* bad map */
653     1004, 1, /* bad map */
654     1005, 1, /* bad map */
655     1006, 1, /* bad map */
656     1007, 100,
657     1008, 1, 
658     1009, 1,
659     1010, 3,
660     1011, 3,
661     1012, 3,
662     1013, 3,
663     1014, 3,
664     1015, 3,
665     1015, 3,
666     1016, 3,
667     1017, 3,
668     1018, 2,
669     1019, 2,
670     1020, 2,
671     1021, 3,
672     1022, 3,
673     1023, 3,
674     1024, 16,
675     1025, 3,
676     1026, 64,
677     1027, 1,
678     1028, 65,
679     1029, 1,
680     1040, 1,
681     /* 1041-1065 */
682     1066, 66,
683     1066, 67,
684     0
685 };
686
687 int yaz_diag_bib1_to_srw (int code)
688 {
689     const int *p = srw_bib1_map;
690     while (*p)
691     {
692         if (code == p[0])
693             return p[1];
694         p += 2;
695     }
696     return 1;
697 }
698
699 int yaz_diag_srw_to_bib1(int code)
700 {
701     const int *p = srw_bib1_map;
702     while (*p)
703     {
704         if (code == p[1])
705             return p[0];
706         p += 2;
707     }
708     return 1;
709 }