Deal with resultCountPrecision - SRU 2.0
[yaz-moved-to-github.git] / src / charneg.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file charneg.c
7  * \brief Implements Z39.50 Charset negotiation utilities
8  *
9  * Helper functions for Character Set and Language Negotiation - 3
10  */
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <stdio.h>
16 #include <yaz/otherinfo.h>
17 #include <yaz/z-charneg.h>
18 #include <yaz/charneg.h>
19 #include <yaz/yaz-util.h>
20 #include <yaz/oid_db.h>
21
22 static Z_External* z_ext_record2(ODR o, const char *buf)
23 {
24     Z_External *p;
25     int len = strlen(buf);
26
27     if (!(p = (Z_External *)odr_malloc(o, sizeof(*p))))
28         return 0;
29     p->descriptor = 0;
30     p->indirect_reference = 0;
31
32     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_id);
33
34     p->which = Z_External_octet;
35     if (!(p->u.octet_aligned = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct))))
36         return 0;
37     if (!(p->u.octet_aligned->buf = (unsigned char *)odr_malloc(o, len)))
38         return 0;
39     p->u.octet_aligned->len = p->u.octet_aligned->size = len;
40     memcpy(p->u.octet_aligned->buf, buf, len);
41
42     return p;
43 }
44
45 static int get_form(const char *charset)
46 {
47     int form = -1;
48
49     if (!yaz_matchstr(charset, "UCS-2"))
50         form = 2;
51     if (!yaz_matchstr(charset, "UCS-4"))
52         form = 4;
53     if (!yaz_matchstr(charset, "UTF-16"))
54         form = 5;
55     if (!yaz_matchstr(charset, "UTF-8"))
56         form = 8;
57
58     return form;
59 }
60
61 static char *set_form(Odr_oid *encoding)
62 {
63     static char *charset = 0;
64     if ( oid_oidlen(encoding) != 6)
65         return 0;
66     if (encoding[5] == 2)
67         charset = "UCS-2";
68     if (encoding[5] == 4)
69         charset = "UCS-4";
70     if (encoding[5] == 5)
71         charset = "UTF-16";
72     if (encoding[5] == 8)
73         charset = "UTF-8";
74     return charset;
75 }
76
77 static Z_OriginProposal_0 *z_get_OriginProposal_0(ODR o, const char *charset)
78 {
79     int form = get_form(charset);
80     Z_OriginProposal_0 *p0 =
81         (Z_OriginProposal_0*)odr_malloc(o, sizeof(*p0));
82
83     memset(p0, 0, sizeof(*p0));
84
85     if (form > 0)
86     {   /* ISO 10646 (UNICODE) */
87         char oidname[20];
88
89         Z_Iso10646 *is = (Z_Iso10646 *) odr_malloc(o, sizeof(*is));
90         p0->which = Z_OriginProposal_0_iso10646;
91         p0->u.iso10646 = is;
92         is->collections = 0;
93         sprintf(oidname, "1.0.10646.1.0.%d", form);
94         is->encodingLevel = odr_getoidbystr(o, oidname);
95     }
96     else
97     {   /* private ones */
98         Z_PrivateCharacterSet *pc =
99             (Z_PrivateCharacterSet *)odr_malloc(o, sizeof(*pc));
100
101         memset(pc, 0, sizeof(*pc));
102
103         p0->which = Z_OriginProposal_0_private;
104         p0->u.zprivate = pc;
105
106         pc->which = Z_PrivateCharacterSet_externallySpecified;
107         pc->u.externallySpecified = z_ext_record2(o, charset);
108     }
109     return p0;
110 }
111
112 static Z_OriginProposal *z_get_OriginProposal(
113     ODR o, const char **charsets, int num_charsets,
114     const char **langs, int num_langs, int selected)
115 {
116     int i;
117     Z_OriginProposal *p = (Z_OriginProposal *) odr_malloc(o, sizeof(*p));
118
119     memset(p, 0, sizeof(*p));
120
121     p->recordsInSelectedCharSets = (bool_t *)odr_malloc(o, sizeof(bool_t));
122     *p->recordsInSelectedCharSets = (selected) ? 1 : 0;
123
124     if (charsets && num_charsets)
125     {
126         p->num_proposedCharSets = num_charsets;
127         p->proposedCharSets =
128             (Z_OriginProposal_0**)
129             odr_malloc(o, num_charsets*sizeof(Z_OriginProposal_0*));
130
131         for (i = 0; i < num_charsets; i++)
132             p->proposedCharSets[i] =
133                 z_get_OriginProposal_0(o, charsets[i]);
134     }
135     if (langs && num_langs)
136     {
137         p->num_proposedlanguages = num_langs;
138         p->proposedlanguages =
139             (char **) odr_malloc(o, num_langs*sizeof(char *));
140
141         for (i = 0; i < num_langs; i++)
142             p->proposedlanguages[i] = (char *)langs[i];
143     }
144     return p;
145 }
146
147 static Z_CharSetandLanguageNegotiation *z_get_CharSetandLanguageNegotiation(
148     ODR o)
149 {
150     Z_CharSetandLanguageNegotiation *p =
151         (Z_CharSetandLanguageNegotiation *) odr_malloc(o, sizeof(*p));
152
153     memset(p, 0, sizeof(*p));
154
155     return p;
156 }
157
158 /* Create EXTERNAL for negotation proposal. Client side */
159 Z_External *yaz_set_proposal_charneg(ODR o,
160                                      const char **charsets, int num_charsets,
161                                      const char **langs, int num_langs,
162                                      int selected)
163 {
164     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
165
166     p->descriptor = 0;
167     p->indirect_reference = 0;
168
169     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_3);
170
171     p->which = Z_External_charSetandLanguageNegotiation;
172     p->u.charNeg3 = z_get_CharSetandLanguageNegotiation(o);
173     p->u.charNeg3->which = Z_CharSetandLanguageNegotiation_proposal;
174     p->u.charNeg3->u.proposal =
175         z_get_OriginProposal(o, charsets, num_charsets,
176                              langs, num_langs, selected);
177
178     return p;
179 }
180
181 Z_External *yaz_set_proposal_charneg_list(ODR o,
182                                           const char *delim,
183                                           const char *charset_list,
184                                           const char *lang_list,
185                                           int selected)
186 {
187     char **charsets_addresses = 0;
188     char **langs_addresses = 0;
189     int charsets_count = 0;
190     int langs_count = 0;
191
192     if (charset_list)
193         nmem_strsplit(odr_getmem(o), delim, charset_list,
194                       &charsets_addresses, &charsets_count);
195     if (lang_list)
196         nmem_strsplit(odr_getmem(o), delim, lang_list,
197                       &langs_addresses, &langs_count);
198     return yaz_set_proposal_charneg(o,
199                                     (const char **) charsets_addresses,
200                                     charsets_count,
201                                     (const char **) langs_addresses,
202                                     langs_count,
203                                     selected);
204 }
205
206
207 /* used by yaz_set_response_charneg */
208 static Z_TargetResponse *z_get_TargetResponse(ODR o, const char *charset,
209                                               const char *lang, int selected)
210 {
211     Z_TargetResponse *p = (Z_TargetResponse *) odr_malloc(o, sizeof(*p));
212     int form = get_form(charset);
213
214     memset(p, 0, sizeof(*p));
215     if (form > 0)
216     {
217         char oidname[20];
218
219         Z_Iso10646 *is = (Z_Iso10646 *) odr_malloc (o, sizeof(*is));
220         p->which = Z_TargetResponse_iso10646;
221         p->u.iso10646 = is;
222         is->collections = 0;
223         sprintf(oidname, "1.0.10646.1.0.%d", form);
224         is->encodingLevel = odr_getoidbystr (o, oidname);
225     }
226     else
227     {
228         Z_PrivateCharacterSet *pc =
229             (Z_PrivateCharacterSet *)odr_malloc(o, sizeof(*pc));
230
231         memset(pc, 0, sizeof(*pc));
232
233         p->which = Z_TargetResponse_private;
234         p->u.zprivate = pc;
235
236         pc->which = Z_PrivateCharacterSet_externallySpecified;
237         pc->u.externallySpecified =
238             z_ext_record2(o, charset);
239     }
240     p->recordsInSelectedCharSets = (bool_t *)odr_malloc(o, sizeof(bool_t));
241     *p->recordsInSelectedCharSets = (selected) ? 1 : 0;
242
243     p->selectedLanguage = lang ? (char *) odr_strdup(o, lang) : 0;
244     return p;
245 }
246
247 /* Create charset response. Server side */
248 Z_External *yaz_set_response_charneg(ODR o, const char *charset,
249                                      const char *lang, int selected)
250 {
251     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
252
253     p->descriptor = 0;
254     p->indirect_reference = 0;
255
256     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_3);
257
258     p->which = Z_External_charSetandLanguageNegotiation;
259     p->u.charNeg3 = z_get_CharSetandLanguageNegotiation(o);
260     p->u.charNeg3->which = Z_CharSetandLanguageNegotiation_response;
261     p->u.charNeg3->u.response = z_get_TargetResponse(o, charset, lang, selected);
262
263     return p;
264 }
265
266 /* Get negotiation from OtherInformation. Client&Server side */
267 Z_CharSetandLanguageNegotiation *yaz_get_charneg_record(Z_OtherInformation *p)
268 {
269     int i;
270
271     if (!p)
272         return 0;
273
274     for (i = 0; i < p->num_elements; i++)
275     {
276         Z_External *pext;
277         if ((p->list[i]->which == Z_OtherInfo_externallyDefinedInfo) &&
278             (pext = p->list[i]->information.externallyDefinedInfo))
279         {
280             if (!oid_oidcmp(pext->direct_reference, yaz_oid_negot_charset_3)
281                 && pext->which == Z_External_charSetandLanguageNegotiation)
282             {
283                 return pext->u.charNeg3;
284             }
285         }
286     }
287     return 0;
288 }
289
290 /* Delete negotiation from OtherInformation. Client&Server side */
291 int yaz_del_charneg_record(Z_OtherInformation **p)
292 {
293     int i;
294
295     if (!*p)
296         return 0;
297
298     for (i = 0; i < (*p)->num_elements; i++)
299     {
300         Z_External *pext;
301         if (((*p)->list[i]->which == Z_OtherInfo_externallyDefinedInfo) &&
302             (pext = (*p)->list[i]->information.externallyDefinedInfo))
303         {
304             if (!oid_oidcmp(pext->direct_reference, yaz_oid_negot_charset_3)
305                 && pext->which == Z_External_charSetandLanguageNegotiation)
306             {
307                 if ((*p)->num_elements <= 1)
308                     *p = 0;
309                 else
310                 {
311                     --((*p)->num_elements);
312                     for (; i < (*p)->num_elements; i++)
313                         (*p)->list[i] = (*p)->list[i+1];
314                 }
315                 return 1;
316             }
317         }
318     }
319     return 0;
320 }
321
322
323 /* Get charsets, langs, selected from negotiation.. Server side */
324 void yaz_get_proposal_charneg(NMEM mem, Z_CharSetandLanguageNegotiation *p,
325                               char ***charsets, int *num_charsets,
326                               char ***langs, int *num_langs, int *selected)
327 {
328     int i;
329     Z_OriginProposal *pro = p->u.proposal;
330
331     if (num_charsets && charsets)
332     {
333         if (pro->num_proposedCharSets)
334         {
335             *num_charsets = pro->num_proposedCharSets;
336
337             (*charsets) = (char **)
338                 nmem_malloc(mem, pro->num_proposedCharSets * sizeof(char *));
339
340             for (i = 0; i < pro->num_proposedCharSets; i++)
341             {
342                 (*charsets)[i] = 0;
343
344                 if (pro->proposedCharSets[i]->which ==
345                     Z_OriginProposal_0_private &&
346                     pro->proposedCharSets[i]->u.zprivate->which ==
347                     Z_PrivateCharacterSet_externallySpecified)
348                 {
349                     Z_External *pext =
350                         pro->proposedCharSets[i]->u.zprivate->u.externallySpecified;
351
352                     if (pext->which == Z_External_octet)
353                     {
354                         (*charsets)[i] = (char *)
355                             nmem_malloc(mem, (1+pext->u.octet_aligned->len) *
356                                         sizeof(char));
357
358                         memcpy((*charsets)[i], pext->u.octet_aligned->buf,
359                                pext->u.octet_aligned->len);
360                         (*charsets)[i][pext->u.octet_aligned->len] = 0;
361                     }
362                 }
363                 else if (pro->proposedCharSets[i]->which ==
364                          Z_OriginProposal_0_iso10646)
365                     (*charsets)[i] = set_form(
366                         pro->proposedCharSets[i]->u.iso10646->encodingLevel);
367             }
368         }
369         else
370             *num_charsets = 0;
371     }
372
373     if (langs && num_langs)
374     {
375         if (pro->num_proposedlanguages)
376         {
377             *num_langs = pro->num_proposedlanguages;
378
379             (*langs) = (char **)
380                 nmem_malloc(mem, pro->num_proposedlanguages * sizeof(char *));
381
382             for (i = 0; i < pro->num_proposedlanguages; i++)
383                 (*langs)[i] = nmem_strdup(mem, pro->proposedlanguages[i]);
384         }
385         else
386             *num_langs = 0;
387     }
388
389     if (pro->recordsInSelectedCharSets && selected)
390         *selected = *pro->recordsInSelectedCharSets;
391 }
392
393 /* Return charset, lang, selected from negotiation.. Client side */
394 void yaz_get_response_charneg(NMEM mem, Z_CharSetandLanguageNegotiation *p,
395                               char **charset, char **lang, int *selected)
396 {
397     Z_TargetResponse *res = p->u.response;
398
399     if (charset && res->which == Z_TargetResponse_private &&
400         res->u.zprivate->which == Z_PrivateCharacterSet_externallySpecified)
401     {
402         Z_External *pext = res->u.zprivate->u.externallySpecified;
403
404         if (pext->which == Z_External_octet)
405         {
406             *charset = (char *)
407                 nmem_malloc(mem, (1+pext->u.octet_aligned->len)*sizeof(char));
408             memcpy(*charset, pext->u.octet_aligned->buf,
409                    pext->u.octet_aligned->len);
410             (*charset)[pext->u.octet_aligned->len] = 0;
411         }
412     }
413     if (charset && res->which == Z_TargetResponse_iso10646)
414         *charset = set_form(res->u.iso10646->encodingLevel);
415     if (lang && res->selectedLanguage)
416         *lang = nmem_strdup(mem, res->selectedLanguage);
417
418     if (selected && res->recordsInSelectedCharSets)
419         *selected = *res->recordsInSelectedCharSets;
420 }
421 /*
422  * Local variables:
423  * c-basic-offset: 4
424  * c-file-style: "Stroustrup"
425  * indent-tabs-mode: nil
426  * End:
427  * vim: shiftwidth=4 tabstop=8 expandtab
428  */
429