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