index set -> context set
[yaz-moved-to-github.git] / src / charneg.c
1 /* 
2  $ $Id: charneg.c,v 1.1 2003-10-27 12:21:30 adam Exp $
3  * Helper functions for Character Set and Language Negotiation - 3
4  */
5
6 #include <stdio.h>
7 #include <yaz/otherinfo.h>
8 #include <yaz/z-charneg.h>
9 #include <yaz/charneg.h>
10 #include <yaz/yaz-util.h>
11
12 static Z_External* z_ext_record2(ODR o, int oid_class, int oid_value,
13                                  const char *buf)
14 {
15     Z_External *p;
16     oident oid;
17     int len = strlen(buf);
18     
19     if (!(p = (Z_External *)odr_malloc(o, sizeof(*p)))) return 0;
20     
21     p->descriptor = 0;
22     p->indirect_reference = 0;
23     
24     oid.proto = PROTO_Z3950;
25     oid.oclass = (enum oid_class) oid_class;
26     oid.value = (enum oid_value) oid_value;
27     p->direct_reference = odr_oiddup(o, oid_getoidbyent(&oid));
28     
29     p->which = Z_External_octet;
30     if (!(p->u.octet_aligned = (Odr_oct *)odr_malloc(o, sizeof(Odr_oct)))) {
31         return 0;
32     }
33     if (!(p->u.octet_aligned->buf = (unsigned char *)odr_malloc(o, len))) {
34         return 0;
35     }
36     p->u.octet_aligned->len = p->u.octet_aligned->size = len;
37     memcpy(p->u.octet_aligned->buf, buf, len);
38         
39     return p;
40 }
41
42 static int get_form(const char *charset)
43 {
44     int form = -1;
45
46
47     if (!yaz_matchstr(charset, "UCS-2"))
48         form = 2;
49     if (!yaz_matchstr(charset, "UCS-4"))
50         form = 4;
51     if (!yaz_matchstr(charset, "UTF-16"))
52         form = 5;
53     if (!yaz_matchstr(charset, "UTF-8"))
54         form = 8;
55
56     return form;
57 }
58
59 static char *set_form (Odr_oid *encoding)
60 {
61     static char *charset = 0;
62     if ( oid_oidlen(encoding) != 6)
63         return 0;
64     if (encoding[5] == 2)
65         charset = "UCS-2";
66     if (encoding[5] == 4)
67         charset = "UCS-4";
68     if (encoding[5] == 5)
69         charset = "UTF-16";
70     if (encoding[5] == 8)
71         charset = "UTF-8";
72     return charset;
73 }
74
75 static Z_OriginProposal_0 *z_get_OriginProposal_0(ODR o, const char *charset)
76 {
77     int form = get_form (charset);
78     Z_OriginProposal_0 *p0 =
79         (Z_OriginProposal_0*)odr_malloc(o, sizeof(*p0));
80
81     memset(p0, 0, sizeof(*p0));
82
83     if (form > 0)
84     {   /* ISO 10646 (UNICODE) */
85         char oidname[20];
86
87         Z_Iso10646 *is = (Z_Iso10646 *) odr_malloc (o, sizeof(*is));
88         p0->which = Z_OriginProposal_0_iso10646;
89         p0->u.iso10646 = is;
90         is->collections = 0;
91         sprintf (oidname, "1.0.10646.1.0.%d", form);
92         is->encodingLevel = odr_getoidbystr (o, oidname);
93     }
94     else
95     {   /* private ones */
96         Z_PrivateCharacterSet *pc =
97             (Z_PrivateCharacterSet *)odr_malloc(o, sizeof(*pc));
98
99         memset(pc, 0, sizeof(*pc));
100         
101         p0->which = Z_OriginProposal_0_private;
102         p0->u.zprivate = pc;
103         
104         pc->which = Z_PrivateCharacterSet_externallySpecified;
105         pc->u.externallySpecified =
106             z_ext_record2(o, CLASS_NEGOT, VAL_ID_CHARSET, charset);
107     }
108     return p0;
109 }
110
111 static Z_OriginProposal *z_get_OriginProposal(
112     ODR o, const char **charsets, int num_charsets,
113     const char **langs, int num_langs, int selected)
114 {       
115     int i;
116     Z_OriginProposal *p = (Z_OriginProposal *) odr_malloc(o, sizeof(*p));
117                 
118     memset(p, 0, sizeof(*p));
119
120     p->recordsInSelectedCharSets = (bool_t *)odr_malloc(o, sizeof(bool_t));
121     *p->recordsInSelectedCharSets = (selected) ? 1:0;
122
123     if (charsets && num_charsets) {             
124         
125         p->num_proposedCharSets = num_charsets;
126         p->proposedCharSets = 
127             (Z_OriginProposal_0**)
128             odr_malloc(o, num_charsets*sizeof(Z_OriginProposal_0*));
129
130         for (i = 0; i<num_charsets; i++)
131             p->proposedCharSets[i] =
132                 z_get_OriginProposal_0(o, charsets[i]);
133     }
134     if (langs && num_langs) {
135         
136         p->num_proposedlanguages = num_langs;
137
138         p->proposedlanguages = 
139             (char **) odr_malloc(o, num_langs*sizeof(char *));
140
141         for (i = 0; i<num_langs; i++) {
142
143             p->proposedlanguages[i] = (char *)langs[i];
144                         
145         }
146     }
147     return p;
148 }
149
150 static Z_CharSetandLanguageNegotiation *z_get_CharSetandLanguageNegotiation(
151     ODR o)
152 {
153     Z_CharSetandLanguageNegotiation *p =
154         (Z_CharSetandLanguageNegotiation *) odr_malloc(o, sizeof(*p));
155     
156     memset(p, 0, sizeof(*p));
157         
158     return p;
159 }
160
161 /* Create EXTERNAL for negotation proposal. Client side */
162 Z_External *yaz_set_proposal_charneg(ODR o,
163                                      const char **charsets, int num_charsets,
164                                      const char **langs, int num_langs,
165                                      int selected)
166 {
167     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
168     oident oid;
169         
170     p->descriptor = 0;
171     p->indirect_reference = 0;  
172
173     oid.proto = PROTO_Z3950;
174     oid.oclass = CLASS_NEGOT;
175     oid.value = VAL_CHARNEG3;
176     p->direct_reference = odr_oiddup(o, oid_getoidbyent(&oid));
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 /* used by yaz_set_response_charneg */
189 static Z_TargetResponse *z_get_TargetResponse(ODR o, const char *charset,
190                                               const char *lang, int selected)
191 {       
192     Z_TargetResponse *p = (Z_TargetResponse *) odr_malloc(o, sizeof(*p));
193     int form = get_form(charset);
194
195     memset(p, 0, sizeof(*p));
196
197     if (form > 0)
198     {
199         char oidname[20];
200
201         Z_Iso10646 *is = (Z_Iso10646 *) odr_malloc (o, sizeof(*is));
202         p->which = Z_TargetResponse_iso10646;
203         p->u.iso10646 = is;
204         is->collections = 0;
205         sprintf (oidname, "1.0.10646.1.0.%d", form);
206         is->encodingLevel = odr_getoidbystr (o, oidname);
207     }
208     else
209     {
210         Z_PrivateCharacterSet *pc =
211             (Z_PrivateCharacterSet *)odr_malloc(o, sizeof(*pc));
212         
213         memset(pc, 0, sizeof(*pc));
214         
215         p->which = Z_TargetResponse_private;
216         p->u.zprivate = pc;
217         
218         pc->which = Z_PrivateCharacterSet_externallySpecified;
219         pc->u.externallySpecified =
220             z_ext_record2(o, CLASS_NEGOT, VAL_ID_CHARSET, charset);
221     }
222     p->recordsInSelectedCharSets = (bool_t *)odr_malloc(o, sizeof(bool_t));
223     *p->recordsInSelectedCharSets = (selected) ? 1:0;
224     
225     p->selectedLanguage = lang ? (char *)odr_strdup(o, lang) : 0;
226     return p;
227 }
228
229 /* Create charset response. Server side */
230 Z_External *yaz_set_response_charneg(ODR o, const char *charset,
231                                      const char *lang, int selected)
232 {
233     Z_External *p = (Z_External *)odr_malloc(o, sizeof(*p));
234     oident oid;
235         
236     p->descriptor = 0;
237     p->indirect_reference = 0;  
238
239     oid.proto = PROTO_Z3950;
240     oid.oclass = CLASS_NEGOT;
241     oid.value = VAL_CHARNEG3;
242     p->direct_reference = odr_oiddup(o, oid_getoidbyent(&oid));
243
244     p->which = Z_External_charSetandLanguageNegotiation;
245     p->u.charNeg3 = z_get_CharSetandLanguageNegotiation(o);
246     p->u.charNeg3->which = Z_CharSetandLanguageNegotiation_response;
247     p->u.charNeg3->u.response = z_get_TargetResponse(o, charset, lang, selected);
248
249     return p;
250 }
251
252 /* Get negotiation from OtherInformation. Client&Server side */
253 Z_CharSetandLanguageNegotiation *yaz_get_charneg_record(Z_OtherInformation *p)
254 {
255     Z_External *pext;
256     int i;
257         
258     if(!p)
259         return 0;
260         
261     for (i=0; i<p->num_elements; i++) {
262         
263         if ((p->list[i]->which == Z_OtherInfo_externallyDefinedInfo) &&
264             (pext = p->list[i]->information.externallyDefinedInfo)) {
265                                         
266             oident *ent = oid_getentbyoid(pext->direct_reference);
267                         
268             if (ent && ent->value == VAL_CHARNEG3 && ent->oclass == CLASS_NEGOT &&
269                 pext->which == Z_External_charSetandLanguageNegotiation) {
270                                 
271                 return pext->u.charNeg3;
272             }
273         }
274     }
275     return 0;
276 }
277
278 /* Get charsets, langs, selected from negotiation.. Server side */
279 void yaz_get_proposal_charneg(NMEM mem, Z_CharSetandLanguageNegotiation *p,
280                               char ***charsets, int *num_charsets,
281                               char ***langs, int *num_langs, int *selected)
282 {
283     int i;
284     Z_OriginProposal *pro = p->u.proposal;
285     
286     if (num_charsets && charsets)
287     {
288         if (pro->num_proposedCharSets)
289         {
290             *num_charsets = pro->num_proposedCharSets;
291             
292             (*charsets) = (char **)
293                 nmem_malloc(mem, pro->num_proposedCharSets * sizeof(char *));
294             
295             for (i=0; i<pro->num_proposedCharSets; i++) 
296             {
297                 (*charsets)[i] = 0;
298                 
299                 if (pro->proposedCharSets[i]->which ==
300                     Z_OriginProposal_0_private &&
301                     pro->proposedCharSets[i]->u.zprivate->which ==
302                     Z_PrivateCharacterSet_externallySpecified) {
303                     
304                     Z_External *pext =
305                         pro->proposedCharSets[i]->u.zprivate->u.externallySpecified;
306                     
307                     if (pext->which == Z_External_octet) {
308                         
309                         (*charsets)[i] = (char *)
310                             nmem_malloc(mem, (1+pext->u.octet_aligned->len) *
311                                         sizeof(char));
312                         
313                         memcpy ((*charsets)[i], pext->u.octet_aligned->buf,
314                                 pext->u.octet_aligned->len);
315                         (*charsets)[i][pext->u.octet_aligned->len] = 0;
316                         
317                     }
318                 }
319                 else if (pro->proposedCharSets[i]->which ==
320                          Z_OriginProposal_0_iso10646)
321                     (*charsets)[i] = set_form (
322                         pro->proposedCharSets[i]->u.iso10646->encodingLevel);
323             }
324         }
325         else
326             *num_charsets = 0;
327     }
328     
329     if (langs && num_langs)
330     {
331         if (pro->num_proposedlanguages)
332         {
333             *num_langs = pro->num_proposedlanguages;
334             
335             (*langs) = (char **)
336                 nmem_malloc(mem, pro->num_proposedlanguages * sizeof(char *));
337             
338             for (i=0; i<pro->num_proposedlanguages; i++)
339                 (*langs)[i] = nmem_strdup(mem, pro->proposedlanguages[i]);
340         }
341         else
342             *num_langs = 0;
343     }
344     
345     if(pro->recordsInSelectedCharSets && selected)
346         *selected = *pro->recordsInSelectedCharSets;
347 }
348
349 /* Return charset, lang, selected from negotiation.. Client side */
350 void yaz_get_response_charneg(NMEM mem, Z_CharSetandLanguageNegotiation *p,
351                               char **charset, char **lang, int *selected)
352 {
353     Z_TargetResponse *res = p->u.response;
354         
355     if (charset && res->which == Z_TargetResponse_private &&
356         res->u.zprivate->which == Z_PrivateCharacterSet_externallySpecified) {
357
358         Z_External *pext = res->u.zprivate->u.externallySpecified;
359         
360         if (pext->which == Z_External_octet) {
361             
362             *charset = (char *)
363                 nmem_malloc(mem, (1+pext->u.octet_aligned->len)*sizeof(char));
364             memcpy (*charset, pext->u.octet_aligned->buf,
365                     pext->u.octet_aligned->len);
366             (*charset)[pext->u.octet_aligned->len] = 0;
367         }       
368     }
369     if (charset && res->which == Z_TargetResponse_iso10646)
370         *charset = set_form (res->u.iso10646->encodingLevel);
371     if (lang && res->selectedLanguage)
372         *lang = nmem_strdup (mem, res->selectedLanguage);
373
374     if(selected && res->recordsInSelectedCharSets)
375         *selected = *res->recordsInSelectedCharSets;
376 }