9701cdac545103db123d78b3338541325777e878
[yaz-moved-to-github.git] / src / charneg.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2011 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)))) return 0;
28     
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     }
38     if (!(p->u.octet_aligned->buf = (unsigned char *)odr_malloc(o, len))) {
39         return 0;
40     }
41     p->u.octet_aligned->len = p->u.octet_aligned->size = len;
42     memcpy(p->u.octet_aligned->buf, buf, len);
43         
44     return p;
45 }
46
47 static int get_form(const char *charset)
48 {
49     int form = -1;
50
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
142         p->proposedlanguages = 
143             (char **) odr_malloc(o, num_langs*sizeof(char *));
144
145         for (i = 0; i<num_langs; i++) {
146
147             p->proposedlanguages[i] = (char *)langs[i];
148                         
149         }
150     }
151     return p;
152 }
153
154 static Z_CharSetandLanguageNegotiation *z_get_CharSetandLanguageNegotiation(
155     ODR o)
156 {
157     Z_CharSetandLanguageNegotiation *p =
158         (Z_CharSetandLanguageNegotiation *) odr_malloc(o, sizeof(*p));
159     
160     memset(p, 0, sizeof(*p));
161         
162     return p;
163 }
164
165 /* Create EXTERNAL for negotation proposal. Client side */
166 Z_External *yaz_set_proposal_charneg(ODR o,
167                                      const char **charsets, int num_charsets,
168                                      const char **langs, int num_langs,
169                                      int selected)
170 {
171     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
172         
173     p->descriptor = 0;
174     p->indirect_reference = 0;  
175
176     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_3);
177
178     p->which = Z_External_charSetandLanguageNegotiation;
179     p->u.charNeg3 = z_get_CharSetandLanguageNegotiation(o);
180     p->u.charNeg3->which = Z_CharSetandLanguageNegotiation_proposal;
181     p->u.charNeg3->u.proposal =
182         z_get_OriginProposal(o, charsets, num_charsets,
183                              langs, num_langs, selected);
184
185     return p;
186 }
187
188 Z_External *yaz_set_proposal_charneg_list(ODR o,
189                                           const char *delim,
190                                           const char *charset_list,
191                                           const char *lang_list,
192                                           int selected)
193 {
194     char **charsets_addresses = 0;
195     char **langs_addresses = 0;
196     int charsets_count = 0;
197     int langs_count = 0;
198     
199     if (charset_list)
200         nmem_strsplit(odr_getmem(o), delim, charset_list,
201                       &charsets_addresses, &charsets_count);
202     if (lang_list)
203         nmem_strsplit(odr_getmem(o), delim, lang_list,
204                       &langs_addresses, &langs_count);    
205     return yaz_set_proposal_charneg(o,
206                                     (const char **) charsets_addresses,
207                                     charsets_count,
208                                     (const char **) langs_addresses,
209                                     langs_count, 
210                                     selected);
211 }
212
213
214 /* used by yaz_set_response_charneg */
215 static Z_TargetResponse *z_get_TargetResponse(ODR o, const char *charset,
216                                               const char *lang, int selected)
217 {       
218     Z_TargetResponse *p = (Z_TargetResponse *) odr_malloc(o, sizeof(*p));
219     int form = get_form(charset);
220
221     memset(p, 0, sizeof(*p));
222
223     if (form > 0)
224     {
225         char oidname[20];
226
227         Z_Iso10646 *is = (Z_Iso10646 *) odr_malloc (o, sizeof(*is));
228         p->which = Z_TargetResponse_iso10646;
229         p->u.iso10646 = is;
230         is->collections = 0;
231         sprintf (oidname, "1.0.10646.1.0.%d", form);
232         is->encodingLevel = odr_getoidbystr (o, oidname);
233     }
234     else
235     {
236         Z_PrivateCharacterSet *pc =
237             (Z_PrivateCharacterSet *)odr_malloc(o, sizeof(*pc));
238         
239         memset(pc, 0, sizeof(*pc));
240         
241         p->which = Z_TargetResponse_private;
242         p->u.zprivate = pc;
243         
244         pc->which = Z_PrivateCharacterSet_externallySpecified;
245         pc->u.externallySpecified =
246             z_ext_record2(o, charset);
247     }
248     p->recordsInSelectedCharSets = (bool_t *)odr_malloc(o, sizeof(bool_t));
249     *p->recordsInSelectedCharSets = (selected) ? 1:0;
250     
251     p->selectedLanguage = lang ? (char *)odr_strdup(o, lang) : 0;
252     return p;
253 }
254
255 /* Create charset response. Server side */
256 Z_External *yaz_set_response_charneg(ODR o, const char *charset,
257                                      const char *lang, int selected)
258 {
259     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
260         
261     p->descriptor = 0;
262     p->indirect_reference = 0;  
263
264     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_3);
265
266     p->which = Z_External_charSetandLanguageNegotiation;
267     p->u.charNeg3 = z_get_CharSetandLanguageNegotiation(o);
268     p->u.charNeg3->which = Z_CharSetandLanguageNegotiation_response;
269     p->u.charNeg3->u.response = z_get_TargetResponse(o, charset, lang, selected);
270
271     return p;
272 }
273
274 /* Get negotiation from OtherInformation. Client&Server side */
275 Z_CharSetandLanguageNegotiation *yaz_get_charneg_record(Z_OtherInformation *p)
276 {
277     int i;
278         
279     if (!p)
280         return 0;
281         
282     for (i = 0; i < p->num_elements; i++) {
283         Z_External *pext;
284         if ((p->list[i]->which == Z_OtherInfo_externallyDefinedInfo) &&
285             (pext = p->list[i]->information.externallyDefinedInfo)) {
286             
287             if (!oid_oidcmp(pext->direct_reference, yaz_oid_negot_charset_3)
288                 && pext->which == Z_External_charSetandLanguageNegotiation)
289             {
290                 return pext->u.charNeg3;
291             }
292         }
293     }
294     return 0;
295 }
296
297 /* Delete negotiation from OtherInformation. Client&Server side */
298 int yaz_del_charneg_record(Z_OtherInformation **p)
299 {
300     int i;
301         
302     if (!*p)
303         return 0;
304         
305     for (i = 0; i < (*p)->num_elements; i++) {
306         Z_External *pext;
307         if (((*p)->list[i]->which == Z_OtherInfo_externallyDefinedInfo) &&
308             (pext = (*p)->list[i]->information.externallyDefinedInfo))
309         {
310             if (!oid_oidcmp(pext->direct_reference, yaz_oid_negot_charset_3)
311                 && pext->which == Z_External_charSetandLanguageNegotiation)
312             {
313                 if ((*p)->num_elements <= 1)
314                     *p = 0;
315                 else
316                 {
317                     --((*p)->num_elements);
318                     for(; i < (*p)->num_elements; i++)
319                         (*p)->list[i] = (*p)->list[i+1];
320                 }
321                 return 1;
322             }
323         }
324     }
325     return 0;
326 }
327
328
329 /* Get charsets, langs, selected from negotiation.. Server side */
330 void yaz_get_proposal_charneg(NMEM mem, Z_CharSetandLanguageNegotiation *p,
331                               char ***charsets, int *num_charsets,
332                               char ***langs, int *num_langs, int *selected)
333 {
334     int i;
335     Z_OriginProposal *pro = p->u.proposal;
336     
337     if (num_charsets && charsets)
338     {
339         if (pro->num_proposedCharSets)
340         {
341             *num_charsets = pro->num_proposedCharSets;
342             
343             (*charsets) = (char **)
344                 nmem_malloc(mem, pro->num_proposedCharSets * sizeof(char *));
345             
346             for (i=0; i<pro->num_proposedCharSets; i++) 
347             {
348                 (*charsets)[i] = 0;
349                 
350                 if (pro->proposedCharSets[i]->which ==
351                     Z_OriginProposal_0_private &&
352                     pro->proposedCharSets[i]->u.zprivate->which ==
353                     Z_PrivateCharacterSet_externallySpecified) {
354                     
355                     Z_External *pext =
356                         pro->proposedCharSets[i]->u.zprivate->u.externallySpecified;
357                     
358                     if (pext->which == Z_External_octet) {
359                         
360                         (*charsets)[i] = (char *)
361                             nmem_malloc(mem, (1+pext->u.octet_aligned->len) *
362                                         sizeof(char));
363                         
364                         memcpy ((*charsets)[i], pext->u.octet_aligned->buf,
365                                 pext->u.octet_aligned->len);
366                         (*charsets)[i][pext->u.octet_aligned->len] = 0;
367                         
368                     }
369                 }
370                 else if (pro->proposedCharSets[i]->which ==
371                          Z_OriginProposal_0_iso10646)
372                     (*charsets)[i] = set_form (
373                         pro->proposedCharSets[i]->u.iso10646->encodingLevel);
374             }
375         }
376         else
377             *num_charsets = 0;
378     }
379     
380     if (langs && num_langs)
381     {
382         if (pro->num_proposedlanguages)
383         {
384             *num_langs = pro->num_proposedlanguages;
385             
386             (*langs) = (char **)
387                 nmem_malloc(mem, pro->num_proposedlanguages * sizeof(char *));
388             
389             for (i=0; i<pro->num_proposedlanguages; i++)
390                 (*langs)[i] = nmem_strdup(mem, pro->proposedlanguages[i]);
391         }
392         else
393             *num_langs = 0;
394     }
395     
396     if(pro->recordsInSelectedCharSets && selected)
397         *selected = *pro->recordsInSelectedCharSets;
398 }
399
400 /* Return charset, lang, selected from negotiation.. Client side */
401 void yaz_get_response_charneg(NMEM mem, Z_CharSetandLanguageNegotiation *p,
402                               char **charset, char **lang, int *selected)
403 {
404     Z_TargetResponse *res = p->u.response;
405         
406     if (charset && res->which == Z_TargetResponse_private &&
407         res->u.zprivate->which == Z_PrivateCharacterSet_externallySpecified) {
408
409         Z_External *pext = res->u.zprivate->u.externallySpecified;
410         
411         if (pext->which == Z_External_octet) {
412             
413             *charset = (char *)
414                 nmem_malloc(mem, (1+pext->u.octet_aligned->len)*sizeof(char));
415             memcpy (*charset, pext->u.octet_aligned->buf,
416                     pext->u.octet_aligned->len);
417             (*charset)[pext->u.octet_aligned->len] = 0;
418         }       
419     }
420     if (charset && res->which == Z_TargetResponse_iso10646)
421         *charset = set_form (res->u.iso10646->encodingLevel);
422     if (lang && res->selectedLanguage)
423         *lang = nmem_strdup (mem, res->selectedLanguage);
424
425     if(selected && res->recordsInSelectedCharSets)
426         *selected = *res->recordsInSelectedCharSets;
427 }
428 /*
429  * Local variables:
430  * c-basic-offset: 4
431  * c-file-style: "Stroustrup"
432  * indent-tabs-mode: nil
433  * End:
434  * vim: shiftwidth=4 tabstop=8 expandtab
435  */
436