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