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