Missing return statements
[yaz-moved-to-github.git] / src / srw.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.9 2003-12-30 00:16:24 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_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
15 {
16     if (val)
17     {
18         xmlDocPtr doc = xmlParseMemory(val,len);
19         if (doc)
20         {
21             xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
22             xmlNodePtr t = xmlDocGetRootElement(doc);
23             xmlAddChild(c, xmlCopyNode(t,1));
24             xmlFreeDoc(doc);
25         }
26     }
27 }
28
29 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
30                             int len)
31 {
32     if (val)
33     {
34         xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
35         xmlNodePtr t = xmlNewTextLen(val, len);
36         xmlAddChild(c, t);
37         return t;
38     }
39     return 0;
40 }
41
42 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
43 {
44     if (val)
45         return xmlNewChild(ptr, 0, elem, val);
46     return 0;
47 }
48
49 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
50 {
51     if (val)
52     {
53         char str[30];
54         sprintf(str, "%d", *val);
55         xmlNewChild(ptr, 0, elem, str);
56     }
57 }
58
59 static int match_element(xmlNodePtr ptr, const char *elem)
60 {
61     if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
62         return 1;
63     return 0;
64 }
65
66 #define CHECK_TYPE 0
67
68 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
69                               char **val, int *len)
70 {
71 #if CHECK_TYPE
72     struct _xmlAttr *attr;
73 #endif
74     if (!match_element(ptr, elem))
75         return 0;
76 #if CHECK_TYPE
77     for (attr = ptr->properties; attr; attr = attr->next)
78         if (!strcmp(attr->name, "type") &&
79             attr->children && attr->children->type == XML_TEXT_NODE)
80         {
81             const char *t = strchr(attr->children->content, ':');
82             if (t)
83                 t = t + 1;
84             else
85                 t = attr->children->content;
86             if (!strcmp(t, "string"))
87                 break;
88         }
89     if (!attr)
90         return 0;
91 #endif
92     ptr = ptr->children;
93     if (!ptr || ptr->type != XML_TEXT_NODE)
94         return 0;
95     *val = odr_strdup(o, ptr->content);
96     if (len)
97         *len = strlen(ptr->content);
98     return 1;
99 }
100
101
102 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
103                             char **val)
104 {
105     return match_xsd_string_n(ptr, elem, o, val, 0);
106 }
107
108 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
109                            char **val, int *len)
110 {
111     xmlBufferPtr buf;
112
113     if (!match_element(ptr, elem))
114         return 0;
115     ptr = ptr->children;
116     if (!ptr)
117         return 0;
118     buf = xmlBufferCreate();
119
120     xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
121
122     *val = odr_malloc(o, buf->use+1);
123     memcpy (*val, buf->content, buf->use);
124     (*val)[buf->use] = '\0';
125
126     if (len)
127         *len = buf->use;
128
129     xmlBufferFree(buf);
130
131     return 1;
132 }
133
134                      
135 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
136 {
137 #if CHECK_TYPE
138     struct _xmlAttr *attr;
139 #endif
140     if (!match_element(ptr, elem))
141         return 0;
142 #if CHECK_TYPE
143     for (attr = ptr->properties; attr; attr = attr->next)
144         if (!strcmp(attr->name, "type") &&
145             attr->children && attr->children->type == XML_TEXT_NODE)
146         {
147             const char *t = strchr(attr->children->content, ':');
148             if (t)
149                 t = t + 1;
150             else
151                 t = attr->children->content;
152             if (!strcmp(t, "integer"))
153                 break;
154         }
155     if (!attr)
156         return 0;
157 #endif
158     ptr = ptr->children;
159     if (!ptr || ptr->type != XML_TEXT_NODE)
160         return 0;
161     *val = odr_intdup(o, atoi(ptr->content));
162     return 1;
163 }
164
165 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
166                           void *client_data, const char *ns)
167 {
168     if (o->direction == ODR_DECODE)
169     {
170         int pack = Z_SRW_recordPacking_string;
171         xmlNodePtr ptr;
172         rec->recordSchema = 0;
173         rec->recordData_buf = 0;
174         rec->recordData_len = 0;
175         rec->recordPosition = 0;
176         for (ptr = pptr->children; ptr; ptr = ptr->next)
177         {
178             char *spack = 0;
179             
180             if (match_xsd_string(ptr, "recordSchema", o, 
181                                  &rec->recordSchema))
182                 ;
183             else if (match_xsd_string(ptr, "recordPacking", o, &spack))
184             {
185                 if (pack && !strcmp(spack, "xml"))
186                     pack = Z_SRW_recordPacking_XML;
187                 if (pack && !strcmp(spack, "string"))
188                     pack = Z_SRW_recordPacking_string;
189             }
190             else if (match_xsd_integer(ptr, "recordPosition", o, 
191                                        &rec->recordPosition))
192                 ;
193             else 
194             {
195                 if (pack == Z_SRW_recordPacking_XML)
196                     match_xsd_XML_n(ptr, "recordData", o, 
197                                     &rec->recordData_buf,
198                                     &rec->recordData_len);
199                 if (pack == Z_SRW_recordPacking_string)
200                     match_xsd_string_n(ptr, "recordData", o, 
201                                        &rec->recordData_buf,
202                                        &rec->recordData_len);
203             }
204         }
205         rec->recordPacking = pack;
206     }
207     else if (o->direction == ODR_ENCODE)
208     {
209         xmlNodePtr ptr = pptr;
210         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
211         switch(rec->recordPacking)
212         {
213         case Z_SRW_recordPacking_string:
214             add_xsd_string(ptr, "recordPacking", "string");
215             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
216                              rec->recordData_len);
217             break;
218         case Z_SRW_recordPacking_XML:
219             add_xsd_string(ptr, "recordPacking", "xml");
220             add_XML_n(ptr, "recordData", rec->recordData_buf,
221                       rec->recordData_len);
222             break;
223         }
224         add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
225     }
226     return 0;
227 }
228
229 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
230                            int *num, void *client_data, const char *ns)
231 {
232     if (o->direction == ODR_DECODE)
233     {
234         int i;
235         xmlNodePtr ptr;
236         *num = 0;
237         for (ptr = pptr->children; ptr; ptr = ptr->next)
238         {
239             if (ptr->type == XML_ELEMENT_NODE &&
240                 !strcmp(ptr->name, "record"))
241                 (*num)++;
242         }
243         if (!*num)
244             return 1;
245         *recs = odr_malloc(o, *num * sizeof(**recs));
246         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
247         {
248             if (ptr->type == XML_ELEMENT_NODE &&
249                 !strcmp(ptr->name, "record"))
250                 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
251         }
252     }
253     else if (o->direction == ODR_ENCODE)
254     {
255         int i;
256         for (i = 0; i < *num; i++)
257         {
258             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
259             yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
260         }
261     }
262     return 0;
263 }
264
265 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
266                                int *num, void *client_data, const char *ns)
267 {
268     if (o->direction == ODR_DECODE)
269     {
270         int i;
271         xmlNodePtr ptr;
272         *num = 0;
273         for (ptr = pptr->children; ptr; ptr = ptr->next)
274         {
275             if (ptr->type == XML_ELEMENT_NODE &&
276                 !strcmp(ptr->name, "diagnostic"))
277                 (*num)++;
278         }
279         if (!*num)
280             return 1;
281         *recs = odr_malloc(o, *num * sizeof(**recs));
282         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
283         {
284             if (ptr->type == XML_ELEMENT_NODE &&
285                 !strcmp(ptr->name, "diagnostic"))
286             {
287                 xmlNodePtr rptr;
288                 (*recs)[i].code = 0;
289                 (*recs)[i].details = 0;
290                 for (rptr = ptr->children; rptr; rptr = rptr->next)
291                 {
292                     if (match_xsd_integer(rptr, "code", o, 
293                                                &(*recs)[i].code))
294                         ;
295                     else if (match_xsd_string(rptr, "details", o, 
296                                               &(*recs)[i].details))
297                         ;
298                 }
299                 i++;
300             }
301         }
302     }
303     else if (o->direction == ODR_ENCODE)
304     {
305         int i;
306         xmlNsPtr ns_diag =
307             xmlNewNs(pptr, "http://www.loc.gov/zing/srw/diagnostics/", "diag");
308         for (i = 0; i < *num; i++)
309         {
310             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
311             add_xsd_integer(rptr, "code", (*recs)[i].code);
312             add_xsd_string(rptr, "details", (*recs)[i].details);
313         }
314     }
315     return 0;
316 }
317
318 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
319                         void *client_data, const char *ns)
320 {
321     if (o->direction == ODR_DECODE)
322     {
323         xmlNodePtr ptr;
324         term->value = 0;
325         term->numberOfRecords = 0;
326         term->displayTerm = 0;
327         for (ptr = pptr->children; ptr; ptr = ptr->next)
328         {
329             char *spack = 0;
330             
331             if (match_xsd_string(ptr, "value", o,  &term->value))
332                 ;
333             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
334                                    &term->numberOfRecords))
335                 ;
336             else if (match_xsd_string(ptr, "displayTerm", o, 
337                                       &term->displayTerm))
338                 ;
339         }
340     }
341     else if (o->direction == ODR_ENCODE)
342     {
343         xmlNodePtr ptr = pptr;
344         add_xsd_string(ptr, "value", term->value);
345         add_xsd_integer(ptr, "value", term->numberOfRecords);
346         add_xsd_string(ptr, "displayTerm", term->displayTerm);
347     }
348     return 0;
349 }
350
351 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
352                          int *num, void *client_data, const char *ns)
353 {
354     if (o->direction == ODR_DECODE)
355     {
356         int i;
357         xmlNodePtr ptr;
358         *num = 0;
359         for (ptr = pptr->children; ptr; ptr = ptr->next)
360         {
361             if (ptr->type == XML_ELEMENT_NODE &&
362                 !strcmp(ptr->name, "term"))
363                 (*num)++;
364         }
365         if (!*num)
366             return 1;
367         *terms = odr_malloc(o, *num * sizeof(**terms));
368         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
369         {
370             if (ptr->type == XML_ELEMENT_NODE &&
371                 !strcmp(ptr->name, "term"))
372                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
373         }
374     }
375     else if (o->direction == ODR_ENCODE)
376     {
377         int i;
378         for (i = 0; i < *num; i++)
379         {
380             xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
381             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
382         }
383     }
384     return 0;
385 }
386
387 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
388                   void *client_data, const char *ns)
389 {
390     xmlNodePtr pptr = vptr;
391     if (o->direction == ODR_DECODE)
392     {
393         Z_SRW_PDU **p = handler_data;
394         xmlNodePtr method = pptr->children;
395
396         while (method && method->type == XML_TEXT_NODE)
397             method = method->next;
398         
399         if (!method)
400             return -1;
401         if (method->type != XML_ELEMENT_NODE)
402             return -1;
403
404         *p = odr_malloc(o, sizeof(**p));
405         (*p)->srw_version = odr_strdup(o, "1.1");
406         
407         if (!strcmp(method->name, "searchRetrieveRequest"))
408         {
409             xmlNodePtr ptr = method->children;
410             Z_SRW_searchRetrieveRequest *req;
411
412             (*p)->which = Z_SRW_searchRetrieve_request;
413             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
414             req->query_type = Z_SRW_query_type_cql;
415             req->query.cql = 0;
416             req->sort_type = Z_SRW_sort_type_none;
417             req->sort.none = 0;
418             req->startRecord = 0;
419             req->maximumRecords = 0;
420             req->recordSchema = 0;
421             req->recordPacking = 0;
422             req->recordXPath = 0;
423             req->resultSetTTL = 0;
424             req->stylesheet = 0;
425             req->database = 0;
426
427             for (; ptr; ptr = ptr->next)
428             {
429                 if (match_xsd_string(ptr, "query", o, 
430                                      &req->query.cql))
431                     req->query_type = Z_SRW_query_type_cql;
432                 else if (match_xsd_string(ptr, "pQuery", o, 
433                                      &req->query.pqf))
434                     req->query_type = Z_SRW_query_type_pqf;
435                 else if (match_xsd_string(ptr, "xQuery", o, 
436                                      &req->query.xcql))
437                     req->query_type = Z_SRW_query_type_xcql;
438                 else if (match_xsd_string(ptr, "sortKeys", o, 
439                                           &req->sort.sortKeys))
440                     req->sort_type = Z_SRW_sort_type_sort;
441                 else if (match_xsd_string(ptr, "recordSchema", o, 
442                                           &req->recordSchema))
443                     ;
444                 else if (match_xsd_string(ptr, "recordPacking", o,
445                                           &req->recordPacking))
446                     ;
447                 else if (match_xsd_string(ptr, "recordXPath", o,
448                                           &req->recordXPath))
449                     ;
450                 else if (match_xsd_integer(ptr, "startRecord", o,
451                                            &req->startRecord))
452                     ;
453                 else if (match_xsd_integer(ptr, "maximumRecords", o,
454                                            &req->maximumRecords))
455                     ;
456                 else if (match_xsd_string(ptr, "stylesheet", o,
457                                            &req->stylesheet))
458                     ;
459                 else if (match_xsd_string(ptr, "database", o,
460                                            &req->database))
461                     ;
462                 else if (match_xsd_string(ptr, "resultSetTTL", o,
463                                            &req->database))
464                     ;
465                 else if (match_xsd_string(ptr, "version", o,
466                                            &(*p)->srw_version))
467                     ;
468                 /* missing is xQuery, xSortKeys .. */
469             }
470         }
471         else if (!strcmp(method->name, "searchRetrieveResponse"))
472         {
473             xmlNodePtr ptr = method->children;
474             Z_SRW_searchRetrieveResponse *res;
475
476             (*p)->which = Z_SRW_searchRetrieve_response;
477             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
478
479             res->numberOfRecords = 0;
480             res->resultSetId = 0;
481             res->resultSetIdleTime = 0;
482             res->records = 0;
483             res->num_records = 0;
484             res->diagnostics = 0;
485             res->num_diagnostics = 0;
486             res->nextRecordPosition = 0;
487
488             for (; ptr; ptr = ptr->next)
489             {
490                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
491                                       &res->numberOfRecords))
492                     ;
493                 else if (match_xsd_string(ptr, "resultSetId", o, 
494                                           &res->resultSetId))
495                     ;
496                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
497                                            &res->resultSetIdleTime))
498                     ;
499                 else if (match_element(ptr, "records"))
500                     yaz_srw_records(o, ptr, &res->records,
501                                     &res->num_records, client_data,
502                                     ns);
503                 else if (match_element(ptr, "diagnostics"))
504                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
505                                         &res->num_diagnostics,
506                                         client_data, ns);
507                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
508                                            &res->nextRecordPosition))
509                     ;
510                 else if (match_xsd_string(ptr, "version", o,
511                                            &(*p)->srw_version))
512                     ;
513             }
514         }
515         else if (!strcmp(method->name, "explainRequest"))
516         {
517             Z_SRW_explainRequest *req;
518             xmlNodePtr ptr = method->children;
519             
520             (*p)->which = Z_SRW_explain_request;
521             req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
522             req->recordPacking = 0;
523             req->database = 0;
524             for (; ptr; ptr = ptr->next)
525             {
526                 if (match_xsd_string(ptr, "database", o,
527                                      &req->database))
528                     ;
529                 else if (match_xsd_string(ptr, "recordPacking", o,
530                                      &req->recordPacking))
531                     ;
532                 else if (match_xsd_string(ptr, "version", o,
533                                            &(*p)->srw_version))
534                     ;
535             }
536         }
537         else if (!strcmp(method->name, "explainResponse"))
538         {
539             Z_SRW_explainResponse *res;
540             xmlNodePtr ptr = method->children;
541
542             (*p)->which = Z_SRW_explain_response;
543             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
544             res->diagnostics = 0;
545             res->num_diagnostics = 0;
546
547             for (; ptr; ptr = ptr->next)
548             {
549                 if (match_element(ptr, "record"))
550                     yaz_srw_record(o, ptr, &res->record, client_data, ns);
551                 else if (match_xsd_string(ptr, "version", o,
552                                           &(*p)->srw_version))
553                     ;
554                 else if (match_element(ptr, "diagnostics"))
555                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
556                                         &res->num_diagnostics,
557                                         client_data, ns);
558                 ;
559             }
560         }
561         else if (!strcmp(method->name, "scanRequest"))
562         {
563             Z_SRW_scanRequest *req;
564             xmlNodePtr ptr = method->children;
565
566             (*p)->which = Z_SRW_scan_request;
567             req = (*p)->u.scan_request = odr_malloc(o, sizeof(*req));
568             req->database = 0;
569             req->scanClause = 0;
570             req->stylesheet = 0;
571             req->responsePosition = 0;
572             req->maximumTerms = 0;
573             
574             for (; ptr; ptr = ptr->next)
575             {
576                 if (match_xsd_string(ptr, "version", o,
577                                      &(*p)->srw_version))
578                     ;
579                 else if (match_xsd_string(ptr, "scanClause", o,
580                                      &req->scanClause))
581                     ;
582                 else if (match_xsd_string(ptr, "database", o,
583                                           &req->database))
584                     ;
585                 else if (match_xsd_string(ptr, "stylesheet", o,
586                                           &req->stylesheet))
587                     ;
588                 else if (match_xsd_integer(ptr, "responsePosition", o,
589                                            &req->responsePosition))
590                     ;
591                 else if (match_xsd_integer(ptr, "maximumTerms", o,
592                                            &req->maximumTerms))
593                     ;
594             }
595         }
596         else if (!strcmp(method->name, "scanResponse"))
597         {
598             Z_SRW_scanResponse *res;
599             xmlNodePtr ptr = method->children;
600
601             (*p)->which = Z_SRW_scan_response;
602             res = (*p)->u.scan_response = odr_malloc(o, sizeof(*res));
603             res->terms = 0;
604             res->num_terms = 0;
605             res->diagnostics = 0;
606             res->num_diagnostics = 0;
607             
608             for (; ptr; ptr = ptr->next)
609             {
610                 if (match_element(ptr, "terms"))
611                     yaz_srw_terms(o, ptr, &res->terms,
612                                   &res->num_terms, client_data,
613                                   ns);
614                 else if (match_element(ptr, "diagnostics"))
615                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
616                                         &res->num_diagnostics,
617                                         client_data, ns);
618                 else if (match_xsd_string(ptr, "version", o,
619                                           &(*p)->srw_version))
620                     ;
621             }
622         }
623         else
624         {
625             *p = 0;
626             return -1;
627         }
628     }
629     else if (o->direction == ODR_ENCODE)
630     {
631         Z_SRW_PDU **p = handler_data;
632         xmlNsPtr ns_srw;
633         
634         if ((*p)->which == Z_SRW_searchRetrieve_request)
635         {
636             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
637             xmlNodePtr ptr = xmlNewChild(pptr, 0,
638                                          "searchRetrieveRequest", 0);
639             ns_srw = xmlNewNs(ptr, ns, "zs");
640             xmlSetNs(ptr, ns_srw);
641
642             if ((*p)->srw_version)
643                 add_xsd_string(ptr, "version", (*p)->srw_version);
644             switch(req->query_type)
645             {
646             case Z_SRW_query_type_cql:
647                 add_xsd_string(ptr, "query", req->query.cql);
648                 break;
649             case Z_SRW_query_type_xcql:
650                 add_xsd_string(ptr, "xQuery", req->query.xcql);
651                 break;
652             case Z_SRW_query_type_pqf:
653                 add_xsd_string(ptr, "pQuery", req->query.pqf);
654                 break;
655             }
656             switch(req->sort_type)
657             {
658             case Z_SRW_sort_type_none:
659                 break;
660             case Z_SRW_sort_type_sort:
661                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
662                 break;
663             case Z_SRW_sort_type_xSort:
664                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
665                 break;
666             }
667             add_xsd_integer(ptr, "startRecord", req->startRecord);
668             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
669             add_xsd_string(ptr, "recordSchema", req->recordSchema);
670             add_xsd_string(ptr, "recordPacking", req->recordPacking);
671             add_xsd_string(ptr, "recordXPath", req->recordXPath);
672             add_xsd_string(ptr, "database", req->database);
673             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
674             add_xsd_string(ptr, "stylesheet", req->stylesheet);
675         }
676         else if ((*p)->which == Z_SRW_searchRetrieve_response)
677         {
678             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
679             xmlNodePtr ptr = xmlNewChild(pptr, 0,
680                                          "searchRetrieveResponse", 0);
681             ns_srw = xmlNewNs(ptr, ns, "zs");
682             xmlSetNs(ptr, ns_srw);
683
684             if ((*p)->srw_version)
685                 add_xsd_string(ptr, "version", (*p)->srw_version);
686             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
687             add_xsd_string(ptr, "resultSetId", res->resultSetId);
688             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
689             if (res->num_records)
690             {
691                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
692                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
693                                 client_data, ns);
694             }
695             if (res->num_diagnostics)
696             {
697                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
698                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
699                                     &res->num_diagnostics, client_data, ns);
700             }
701             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
702         }
703         else if ((*p)->which == Z_SRW_explain_request)
704         {
705             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
706             ns_srw = xmlNewNs(ptr, ns, "zs");
707             xmlSetNs(ptr, ns_srw);
708
709             add_xsd_string(ptr, "version", (*p)->srw_version);
710         }
711         else if ((*p)->which == Z_SRW_explain_response)
712         {
713             Z_SRW_explainResponse *res = (*p)->u.explain_response;
714             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
715             ns_srw = xmlNewNs(ptr, ns, "zs");
716             xmlSetNs(ptr, ns_srw);
717
718             add_xsd_string(ptr, "version", (*p)->srw_version);
719             if (1)
720             {
721                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
722                 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
723             }
724             if (res->num_diagnostics)
725             {
726                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
727                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
728                                     &res->num_diagnostics, client_data, ns);
729             }
730         }
731         else if ((*p)->which == Z_SRW_scan_request)
732         {
733             Z_SRW_scanRequest *req = (*p)->u.scan_request;
734             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
735             ns_srw = xmlNewNs(ptr, ns, "zs");
736             xmlSetNs(ptr, ns_srw);
737
738             add_xsd_string(ptr, "version", (*p)->srw_version);
739             add_xsd_string(ptr, "scanClause", req->scanClause);
740             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
741             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
742             add_xsd_string(ptr, "stylesheet", req->stylesheet);
743         }
744         else if ((*p)->which == Z_SRW_scan_response)
745         {
746             Z_SRW_scanResponse *res = (*p)->u.scan_response;
747             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
748             ns_srw = xmlNewNs(ptr, ns, "zs");
749             xmlSetNs(ptr, ns_srw);
750
751             add_xsd_string(ptr, "version", (*p)->srw_version);
752
753             if (res->num_terms)
754             {
755                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
756                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
757                               client_data, ns);
758             }
759             if (res->num_diagnostics)
760             {
761                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
762                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
763                                     &res->num_diagnostics, client_data, ns);
764             }
765         }
766         else
767             return -1;
768
769     }
770     return 0;
771 }
772
773 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
774 {
775     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
776
777     sr->srw_version = odr_strdup(o, "1.1");
778     sr->which = which;
779     switch(which)
780     {
781     case Z_SRW_searchRetrieve_request:
782         sr->u.request = (Z_SRW_searchRetrieveRequest *)
783             odr_malloc(o, sizeof(*sr->u.request));
784         sr->u.request->query_type = Z_SRW_query_type_cql;
785         sr->u.request->query.cql = 0;
786         sr->u.request->sort_type = Z_SRW_sort_type_none;
787         sr->u.request->sort.none = 0;
788         sr->u.request->startRecord = 0;
789         sr->u.request->maximumRecords = 0;
790         sr->u.request->recordSchema = 0;
791         sr->u.request->recordPacking = 0;
792         sr->u.request->recordXPath = 0;
793         sr->u.request->database = 0;
794         sr->u.request->resultSetTTL = 0;
795         sr->u.request->stylesheet = 0;
796         break;
797     case Z_SRW_searchRetrieve_response:
798         sr->u.response = (Z_SRW_searchRetrieveResponse *)
799             odr_malloc(o, sizeof(*sr->u.response));
800         sr->u.response->numberOfRecords = 0;
801         sr->u.response->resultSetId = 0;
802         sr->u.response->resultSetIdleTime = 0;
803         sr->u.response->records = 0;
804         sr->u.response->num_records = 0;
805         sr->u.response->diagnostics = 0;
806         sr->u.response->num_diagnostics = 0;
807         sr->u.response->nextRecordPosition = 0;
808         break;
809     case Z_SRW_explain_request:
810         sr->u.explain_request = (Z_SRW_explainRequest *)
811             odr_malloc(o, sizeof(*sr->u.explain_request));
812         sr->u.explain_request->recordPacking = 0;
813         sr->u.explain_request->database = 0;
814         break;
815     case Z_SRW_explain_response:
816         sr->u.explain_response = (Z_SRW_explainResponse *)
817             odr_malloc(o, sizeof(*sr->u.explain_response));
818         sr->u.explain_response->record.recordData_buf = 0;
819         sr->u.explain_response->record.recordData_len = 0;
820         sr->u.explain_response->record.recordSchema = 0;
821         sr->u.explain_response->record.recordPosition = 0;
822         sr->u.explain_response->record.recordPacking =
823             Z_SRW_recordPacking_string;
824         sr->u.explain_response->diagnostics = 0;
825         sr->u.explain_response->num_diagnostics = 0;
826     }
827     return sr;
828 }
829
830 #endif
831
832
833 static struct {
834     int code;
835     const char *msg;
836 } yaz_srw_codes [] = {
837 {1, "Permanent system error"}, 
838 {2, "System temporarily unavailable"}, 
839 {3, "Authentication error"}, 
840 /* Diagnostics Relating to CQL */
841 {10, "Illegal query"}, 
842 {11, "Unsupported query type (XCQL vs CQL)"}, 
843 {12, "Too many characters in query"}, 
844 {13, "Unbalanced or illegal use of parentheses"}, 
845 {14, "Unbalanced or illegal use of quotes"}, 
846 {15, "Illegal or unsupported context set"}, 
847 {16, "Illegal or unsupported index"}, 
848 {17, "Illegal or unsupported combination of index and context set"}, 
849 {18, "Illegal or unsupported combination of indexes"}, 
850 {19, "Illegal or unsupported relation"}, 
851 {20, "Illegal or unsupported relation modifier"}, 
852 {21, "Illegal or unsupported combination of relation modifers"}, 
853 {22, "Illegal or unsupported combination of relation and index"}, 
854 {23, "Too many characters in term"}, 
855 {24, "Illegal combination of relation and term"}, 
856 {25, "Special characters not quoted in term"}, 
857 {26, "Non special character escaped in term"}, 
858 {27, "Empty term unsupported"}, 
859 {28, "Masking character not supported"}, 
860 {29, "Masked words too short"}, 
861 {30, "Too many masking characters in term"}, 
862 {31, "Anchoring character not supported"}, 
863 {32, "Anchoring character in illegal or unsupported position"}, 
864 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
865 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
866 {35, "Terms only exclusion (stop) words"}, 
867 {36, "Term in invalid format for index or relation"}, 
868 {37, "Illegal or unsupported boolean operator"}, 
869 {38, "Too many boolean operators in query"}, 
870 {39, "Proximity not supported"}, 
871 {40, "Illegal or unsupported proximity relation"}, 
872 {41, "Illegal or unsupported proximity distance"}, 
873 {42, "Illegal or unsupported proximity unit"}, 
874 {43, "Illegal or unsupported proximity ordering"}, 
875 {44, "Illegal or unsupported combination of proximity modifiers"}, 
876 {45, "context set name (prefix) assigned to multiple identifiers"}, 
877 /* Diagnostics Relating to Result Sets */
878 {50, "Result sets not supported"}, 
879 {51, "Result set does not exist"}, 
880 {52, "Result set temporarily unavailable"}, 
881 {53, "Result sets only supported for retrieval"}, 
882 {54, "Retrieval may only occur from an existing result set"}, 
883 {55, "Combination of result sets with search terms not supported"}, 
884 {56, "Only combination of single result set with search terms supported"}, 
885 {57, "Result set created but no records available"}, 
886 {58, "Result set created with unpredictable partial results available"}, 
887 {59, "Result set created with valid partial results available"}, 
888 /* Diagnostics Relating to Records */
889 {60, "Too many records retrieved"}, 
890 {61, "First record position out of range"}, 
891 {62, "Negative number of records requested"}, 
892 {63, "System error in retrieving records"}, 
893 {64, "Record temporarily unavailable"}, 
894 {65, "Record does not exist"}, 
895 {66, "Unknown schema for retrieval"}, 
896 {67, "Record not available in this schema"}, 
897 {68, "Not authorised to send record"}, 
898 {69, "Not authorised to send record in this schema"}, 
899 {70, "Record too large to send"}, 
900 /* Diagnostics Relating to Sorting */
901 {80, "Sort not supported"}, 
902 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
903 {82, "Illegal or unsupported sort sequence"}, 
904 {83, "Too many records"}, 
905 {84, "Too many sort keys"}, 
906 {85, "Duplicate sort keys"}, 
907 {86, "Incompatible record formats"}, 
908 {87, "Unsupported schema for sort"}, 
909 {88, "Unsupported tag path for sort"}, 
910 {89, "Tag path illegal or unsupported for schema"}, 
911 {90, "Illegal or unsupported direction value"}, 
912 {91, "Illegal or unsupported case value"}, 
913 {92, "Illegal or unsupported missing value action"}, 
914 /* Diagnostics Relating to Explain */
915 {100, "Explain not supported"}, 
916 {101, "Explain request type not supported (SOAP vs GET)"}, 
917 {102, "Explain record temporarily unavailable"},
918 {0, 0}
919 };
920
921 const char *yaz_diag_srw_str (int code)
922 {
923     int i;
924     for (i = 0; yaz_srw_codes[i].code; i++)
925         if (yaz_srw_codes[i].code == code)
926             return yaz_srw_codes[i].msg;
927     return 0;
928 }
929
930
931 /* bib1:srw */
932 static int srw_bib1_map[] = {
933     1, 1,
934     2, 2,
935     3, 11,
936     4, 35,
937     5, 12,
938     6, 38,
939     7, 30,
940     8, 32,
941     9, 29,
942     10, 10,
943     11, 12,
944     11, 23,
945     12, 60,
946     13, 61,
947     13, 62,
948     14, 63,
949     14, 64,
950     14, 65,
951     15, 68,
952     15, 69,
953     16, 70,
954     17, 70,
955     18, 50,
956     19, 55,
957     20, 56, 
958     21, 52,
959     22, 50,
960     23, 1,  /* bad map */
961     24, 63, /* bad map */
962     25, 63, /* bad map */
963     26, 63, /* bad map */
964     27, 51,
965     28, 52,
966     29, 52,
967     30, 51,
968     31, 57,
969     32, 58,
970     33, 59,
971     100, 1, /* bad map */
972     101, 3,
973     102, 3,
974     103, 3,
975     104, 3,
976     105, 3, 
977     106, 66,
978     107, 11,
979     108, 10,
980     108, 13,
981     108, 14,
982     108, 25,
983     108, 26,
984     108, 27,
985     108, 45,
986         
987     109, 1,
988     110, 37,
989     111, 1,
990     112, 58,
991     113, 10,
992     114, 16,
993     115, 16,
994     116, 16,
995     117, 19,
996     118, 22,
997     119, 32,
998     119, 31,
999     120, 28,
1000     121, 15,
1001     122, 32,
1002     123, 22,
1003     123, 17,
1004     123, 18,
1005     124, 24,
1006     125, 36,
1007     126, 36, 
1008     127, 36,
1009     128, 51,
1010     129, 39,
1011     130, 43,
1012     131, 40,
1013     132, 42,
1014     201, 44,
1015     201, 33,
1016     201, 34,
1017     202, 41,
1018     203, 43,
1019     205, 1,  /* bad map */
1020     206, 1,  /* bad map */
1021     207, 89,
1022     208, 1,  /* bad map */
1023     209, 80,
1024     210, 80,
1025     210, 81,
1026     211, 84,
1027     212, 85,
1028     213, 92,
1029     214, 90,
1030     215, 91,
1031     216, 92,
1032     217, 63,
1033     218, 1,  /* bad map */
1034     219, 1,  /* bad map */
1035     220, 1,  /* bad map */
1036     221, 1,  /* bad map */
1037     222, 1,  /* bad map */
1038     223, 1,  /* bad map */
1039     224, 1,  /* bad map */
1040     225, 1,  /* bad map */
1041     226, 1,  /* bad map */
1042     227, 66,
1043     228, 1,  /* bad map */
1044     229, 36,
1045     230, 83,
1046     231, 89,
1047     232, 1,
1048     233, 1, /* bad map */
1049     234, 1, /* bad map */
1050     235, 2,
1051     236, 3, 
1052     237, 82,
1053     238, 67,
1054     239, 66,
1055     240, 1, /* bad map */
1056     241, 1, /* bad map */
1057     242, 70,
1058     243, 1, /* bad map */
1059     244, 66,
1060     245, 10,
1061     246, 10,
1062     247, 10,
1063     1001, 1, /* bad map */
1064     1002, 1, /* bad map */
1065     1003, 1, /* bad map */
1066     1004, 1, /* bad map */
1067     1005, 1, /* bad map */
1068     1006, 1, /* bad map */
1069     1007, 100,
1070     1008, 1, 
1071     1009, 1,
1072     1010, 3,
1073     1011, 3,
1074     1012, 3,
1075     1013, 3,
1076     1014, 3,
1077     1015, 3,
1078     1015, 3,
1079     1016, 3,
1080     1017, 3,
1081     1018, 2,
1082     1019, 2,
1083     1020, 2,
1084     1021, 3,
1085     1022, 3,
1086     1023, 3,
1087     1024, 16,
1088     1025, 3,
1089     1026, 64,
1090     1027, 1,
1091     1028, 65,
1092     1029, 1,
1093     1040, 1,
1094     /* 1041-1065 */
1095     1066, 66,
1096     1066, 67,
1097     0
1098 };
1099
1100 int yaz_diag_bib1_to_srw (int code)
1101 {
1102     const int *p = srw_bib1_map;
1103     while (*p)
1104     {
1105         if (code == p[0])
1106             return p[1];
1107         p += 2;
1108     }
1109     return 1;
1110 }
1111
1112 int yaz_diag_srw_to_bib1(int code)
1113 {
1114     const int *p = srw_bib1_map;
1115     while (*p)
1116     {
1117         if (code == p[1])
1118             return p[0];
1119         p += 2;
1120     }
1121     return 1;
1122 }
1123