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