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