Update source headers for 2008. Omit CVS ID keyword subst.
[yaz-moved-to-github.git] / src / charneg.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2008 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /** 
7  * \file charneg.c
8  * \brief Implements Z39.50 Charset negotiation utilities
9  *
10  * Helper functions for Character Set and Language Negotiation - 3
11  */
12 #include <stdio.h>
13 #include <yaz/otherinfo.h>
14 #include <yaz/z-charneg.h>
15 #include <yaz/charneg.h>
16 #include <yaz/yaz-util.h>
17 #include <yaz/oid_db.h>
18
19 static Z_External* z_ext_record2(ODR o, const char *buf)
20 {
21     Z_External *p;
22     int len = strlen(buf);
23     
24     if (!(p = (Z_External *)odr_malloc(o, sizeof(*p)))) return 0;
25     
26     p->descriptor = 0;
27     p->indirect_reference = 0;
28     
29     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_id);
30     
31     p->which = Z_External_octet;
32     if (!(p->u.octet_aligned = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct)))) {
33         return 0;
34     }
35     if (!(p->u.octet_aligned->buf = (unsigned char *)odr_malloc(o, len))) {
36         return 0;
37     }
38     p->u.octet_aligned->len = p->u.octet_aligned->size = len;
39     memcpy(p->u.octet_aligned->buf, buf, len);
40         
41     return p;
42 }
43
44 static int get_form(const char *charset)
45 {
46     int form = -1;
47
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
139         p->proposedlanguages = 
140             (char **) odr_malloc(o, num_langs*sizeof(char *));
141
142         for (i = 0; i<num_langs; i++) {
143
144             p->proposedlanguages[i] = (char *)langs[i];
145                         
146         }
147     }
148     return p;
149 }
150
151 static Z_CharSetandLanguageNegotiation *z_get_CharSetandLanguageNegotiation(
152     ODR o)
153 {
154     Z_CharSetandLanguageNegotiation *p =
155         (Z_CharSetandLanguageNegotiation *) odr_malloc(o, sizeof(*p));
156     
157     memset(p, 0, sizeof(*p));
158         
159     return p;
160 }
161
162 /* Create EXTERNAL for negotation proposal. Client side */
163 Z_External *yaz_set_proposal_charneg(ODR o,
164                                      const char **charsets, int num_charsets,
165                                      const char **langs, int num_langs,
166                                      int selected)
167 {
168     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
169         
170     p->descriptor = 0;
171     p->indirect_reference = 0;  
172
173     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_3);
174
175     p->which = Z_External_charSetandLanguageNegotiation;
176     p->u.charNeg3 = z_get_CharSetandLanguageNegotiation(o);
177     p->u.charNeg3->which = Z_CharSetandLanguageNegotiation_proposal;
178     p->u.charNeg3->u.proposal =
179         z_get_OriginProposal(o, charsets, num_charsets,
180                              langs, num_langs, selected);
181
182     return p;
183 }
184
185 Z_External *yaz_set_proposal_charneg_list(ODR o,
186                                           const char *delim,
187                                           const char *charset_list,
188                                           const char *lang_list,
189                                           int selected)
190 {
191     char **charsets_addresses = 0;
192     char **langs_addresses = 0;
193     int charsets_count = 0;
194     int langs_count = 0;
195     
196     if (charset_list)
197         nmem_strsplit(odr_getmem(o), delim, charset_list,
198                       &charsets_addresses, &charsets_count);
199     if (lang_list)
200         nmem_strsplit(odr_getmem(o), delim, lang_list,
201                       &langs_addresses, &langs_count);    
202     return yaz_set_proposal_charneg(o,
203                                     (const char **) charsets_addresses,
204                                     charsets_count,
205                                     (const char **) langs_addresses,
206                                     langs_count, 
207                                     selected);
208 }
209
210
211 /* used by yaz_set_response_charneg */
212 static Z_TargetResponse *z_get_TargetResponse(ODR o, const char *charset,
213                                               const char *lang, int selected)
214 {       
215     Z_TargetResponse *p = (Z_TargetResponse *) odr_malloc(o, sizeof(*p));
216     int form = get_form(charset);
217
218     memset(p, 0, sizeof(*p));
219
220     if (form > 0)
221     {
222         char oidname[20];
223
224         Z_Iso10646 *is = (Z_Iso10646 *) odr_malloc (o, sizeof(*is));
225         p->which = Z_TargetResponse_iso10646;
226         p->u.iso10646 = is;
227         is->collections = 0;
228         sprintf (oidname, "1.0.10646.1.0.%d", form);
229         is->encodingLevel = odr_getoidbystr (o, oidname);
230     }
231     else
232     {
233         Z_PrivateCharacterSet *pc =
234             (Z_PrivateCharacterSet *)odr_malloc(o, sizeof(*pc));
235         
236         memset(pc, 0, sizeof(*pc));
237         
238         p->which = Z_TargetResponse_private;
239         p->u.zprivate = pc;
240         
241         pc->which = Z_PrivateCharacterSet_externallySpecified;
242         pc->u.externallySpecified =
243             z_ext_record2(o, charset);
244     }
245     p->recordsInSelectedCharSets = (bool_t *)odr_malloc(o, sizeof(bool_t));
246     *p->recordsInSelectedCharSets = (selected) ? 1:0;
247     
248     p->selectedLanguage = lang ? (char *)odr_strdup(o, lang) : 0;
249     return p;
250 }
251
252 /* Create charset response. Server side */
253 Z_External *yaz_set_response_charneg(ODR o, const char *charset,
254                                      const char *lang, int selected)
255 {
256     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
257         
258     p->descriptor = 0;
259     p->indirect_reference = 0;  
260
261     p->direct_reference = odr_oiddup(o, yaz_oid_negot_charset_3);
262
263     p->which = Z_External_charSetandLanguageNegotiation;
264     p->u.charNeg3 = z_get_CharSetandLanguageNegotiation(o);
265     p->u.charNeg3->which = Z_CharSetandLanguageNegotiation_response;
266     p->u.charNeg3->u.response = z_get_TargetResponse(o, charset, lang, selected);
267
268     return p;
269 }
270
271 /* Get negotiation from OtherInformation. Client&Server side */
272 Z_CharSetandLanguageNegotiation *yaz_get_charneg_record(Z_OtherInformation *p)
273 {
274     int i;
275         
276     if (!p)
277         return 0;
278         
279     for (i = 0; i < p->num_elements; i++) {
280         Z_External *pext;
281         if ((p->list[i]->which == Z_OtherInfo_externallyDefinedInfo) &&
282             (pext = p->list[i]->information.externallyDefinedInfo)) {
283             
284             if (!oid_oidcmp(pext->direct_reference, yaz_oid_negot_charset_3)
285                 && pext->which == Z_External_charSetandLanguageNegotiation)
286             {
287                 return pext->u.charNeg3;
288             }
289         }
290     }
291     return 0;
292 }
293
294 /* Delete negotiation from OtherInformation. Client&Server side */
295 int yaz_del_charneg_record(Z_OtherInformation **p)
296 {
297     int i;
298         
299     if (!*p)
300         return 0;
301         
302     for (i = 0; i < (*p)->num_elements; i++) {
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                 }
367                 else if (pro->proposedCharSets[i]->which ==
368                          Z_OriginProposal_0_iso10646)
369                     (*charsets)[i] = set_form (
370                         pro->proposedCharSets[i]->u.iso10646->encodingLevel);
371             }
372         }
373         else
374             *num_charsets = 0;
375     }
376     
377     if (langs && num_langs)
378     {
379         if (pro->num_proposedlanguages)
380         {
381             *num_langs = pro->num_proposedlanguages;
382             
383             (*langs) = (char **)
384                 nmem_malloc(mem, pro->num_proposedlanguages * sizeof(char *));
385             
386             for (i=0; i<pro->num_proposedlanguages; i++)
387                 (*langs)[i] = nmem_strdup(mem, pro->proposedlanguages[i]);
388         }
389         else
390             *num_langs = 0;
391     }
392     
393     if(pro->recordsInSelectedCharSets && selected)
394         *selected = *pro->recordsInSelectedCharSets;
395 }
396
397 /* Return charset, lang, selected from negotiation.. Client side */
398 void yaz_get_response_charneg(NMEM mem, Z_CharSetandLanguageNegotiation *p,
399                               char **charset, char **lang, int *selected)
400 {
401     Z_TargetResponse *res = p->u.response;
402         
403     if (charset && res->which == Z_TargetResponse_private &&
404         res->u.zprivate->which == Z_PrivateCharacterSet_externallySpecified) {
405
406         Z_External *pext = res->u.zprivate->u.externallySpecified;
407         
408         if (pext->which == Z_External_octet) {
409             
410             *charset = (char *)
411                 nmem_malloc(mem, (1+pext->u.octet_aligned->len)*sizeof(char));
412             memcpy (*charset, pext->u.octet_aligned->buf,
413                     pext->u.octet_aligned->len);
414             (*charset)[pext->u.octet_aligned->len] = 0;
415         }       
416     }
417     if (charset && res->which == Z_TargetResponse_iso10646)
418         *charset = set_form (res->u.iso10646->encodingLevel);
419     if (lang && res->selectedLanguage)
420         *lang = nmem_strdup (mem, res->selectedLanguage);
421
422     if(selected && res->recordsInSelectedCharSets)
423         *selected = *res->recordsInSelectedCharSets;
424 }
425 /*
426  * Local variables:
427  * c-basic-offset: 4
428  * indent-tabs-mode: nil
429  * End:
430  * vim: shiftwidth=4 tabstop=8 expandtab
431  */
432