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