d4180dd6d9171fa24c5fa00bb8e2bf5408f73da9
[yaz-moved-to-github.git] / src / record_render.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file record_render.c
7  * \brief Render Z39.50 records (NamePlusRecord)
8  */
9
10 #include <assert.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include <yaz/marcdisp.h>
15 #include <yaz/record_render.h>
16 #include <yaz/yaz-iconv.h>
17 #include <yaz/proto.h>
18 #include <yaz/oid_db.h>
19
20 static yaz_iconv_t iconv_create_charset(const char *record_charset)
21 {
22     char to[40];
23     char from[40];
24     yaz_iconv_t cd = 0;
25
26     *from = '\0';
27     strcpy(to, "UTF-8");
28     if (record_charset && *record_charset)
29     {
30         /* Use "from,to" or just "from" */
31         const char *cp = strchr(record_charset, ',');
32         size_t clen = strlen(record_charset);
33         if (cp && cp[1])
34         {
35             strncpy( to, cp+1, sizeof(to)-1);
36             to[sizeof(to)-1] = '\0';
37             clen = cp - record_charset;
38         }
39         if (clen > sizeof(from)-1)
40             clen = sizeof(from)-1;
41         
42         if (clen)
43             strncpy(from, record_charset, clen);
44         from[clen] = '\0';
45     }
46     if (*from && *to)
47         cd = yaz_iconv_open(to, from);
48     return cd;
49 }
50
51 static const char *return_marc_record(WRBUF wrbuf,
52                                       int marc_type,
53                                       int *len,
54                                       const char *buf, int sz,
55                                       const char *record_charset)
56 {
57     yaz_iconv_t cd = iconv_create_charset(record_charset);
58     yaz_marc_t mt = yaz_marc_create();
59     const char *ret_string = 0;
60
61     if (cd)
62         yaz_marc_iconv(mt, cd);
63     yaz_marc_xml(mt, marc_type);
64     if (yaz_marc_decode_wrbuf(mt, buf, sz, wrbuf) > 0)
65     {
66         if (len)
67             *len = wrbuf_len(wrbuf);
68         ret_string = wrbuf_cstr(wrbuf);
69     }
70     yaz_marc_destroy(mt);
71     if (cd)
72         yaz_iconv_close(cd);
73     return ret_string;
74 }
75
76 static const char *return_opac_record(WRBUF wrbuf,
77                                       int marc_type,
78                                       int *len,
79                                       Z_OPACRecord *opac_rec,
80                                       const char *record_charset)
81 {
82     yaz_iconv_t cd = iconv_create_charset(record_charset);
83     yaz_marc_t mt = yaz_marc_create();
84
85     if (cd)
86         yaz_marc_iconv(mt, cd);
87     yaz_marc_xml(mt, marc_type);
88
89     yaz_opac_decode_wrbuf(mt, opac_rec, wrbuf);
90     yaz_marc_destroy(mt);
91
92     if (cd)
93         yaz_iconv_close(cd);
94     if (len)
95         *len = wrbuf_len(wrbuf);
96     return wrbuf_cstr(wrbuf);
97 }
98
99 static const char *return_string_record(WRBUF wrbuf,
100                                         int *len,
101                                         const char *buf, int sz,
102                                         const char *record_charset)
103 {
104     yaz_iconv_t cd = iconv_create_charset(record_charset);
105
106     if (cd)
107     {
108         wrbuf_iconv_write(wrbuf, cd, buf, sz);
109         wrbuf_iconv_reset(wrbuf, cd);
110
111         buf = wrbuf_cstr(wrbuf);
112         sz = wrbuf_len(wrbuf);
113         yaz_iconv_close(cd);
114     }
115     if (len)
116         *len = sz;
117     return buf;
118 }
119
120 static const char *return_record_wrbuf(WRBUF wrbuf, int *len,
121                                        Z_NamePlusRecord *npr,
122                                        int marctype, const char *charset)
123 {
124     Z_External *r = (Z_External *) npr->u.databaseRecord;
125     const Odr_oid *oid = r->direct_reference;
126
127     wrbuf_rewind(wrbuf);
128     /* render bibliographic record .. */
129     if (r->which == Z_External_OPAC)
130     {
131         return return_opac_record(wrbuf, marctype, len,
132                                   r->u.opac, charset);
133     }
134     if (r->which == Z_External_sutrs)
135         return return_string_record(wrbuf, len,
136                                     (char*) r->u.sutrs->buf,
137                                     r->u.sutrs->len,
138                                     charset);
139     else if (r->which == Z_External_octet)
140     {
141         if (yaz_oid_is_iso2709(oid))
142         {
143             const char *ret_buf = return_marc_record(
144                 wrbuf, marctype, len,
145                 (const char *) r->u.octet_aligned->buf,
146                 r->u.octet_aligned->len,
147                 charset);
148             if (ret_buf)
149                 return ret_buf;
150             /* bad ISO2709. Return fail unless raw (ISO2709) is wanted */
151             if (marctype != YAZ_MARC_ISO2709)
152                 return 0;
153         }
154         return return_string_record(wrbuf, len,
155                                     (const char *) r->u.octet_aligned->buf,
156                                     r->u.octet_aligned->len,
157                                     charset);
158     }
159     else if (r->which == Z_External_grs1)
160     {
161         yaz_display_grs1(wrbuf, r->u.grs1, 0);
162         return return_string_record(wrbuf, len,
163                                     wrbuf_buf(wrbuf),
164                                     wrbuf_len(wrbuf),
165                                     charset);
166     }
167     return 0;
168 }
169     
170 static const char *get_record_format(WRBUF wrbuf, int *len,
171                                      Z_NamePlusRecord *npr,
172                                      int marctype, const char *charset,
173                                      const char *format)
174 {
175     const char *res = return_record_wrbuf(wrbuf, len, npr, marctype, charset);
176 #if YAZ_HAVE_XML2
177     if (*format == '1' && len)
178     {
179         /* try to XML format res */
180         xmlDocPtr doc;
181         xmlKeepBlanksDefault(0); /* get get xmlDocFormatMemory to work! */
182         doc = xmlParseMemory(res, *len);
183         if (doc)
184         {
185             xmlChar *xml_mem;
186             int xml_size;
187             xmlDocDumpFormatMemory(doc, &xml_mem, &xml_size, 1);
188             wrbuf_rewind(wrbuf);
189             wrbuf_write(wrbuf, (const char *) xml_mem, xml_size);
190             xmlFree(xml_mem);
191             xmlFreeDoc(doc);
192             res = wrbuf_cstr(wrbuf);
193             *len = wrbuf_len(wrbuf);
194         } 
195     }
196 #endif
197     return res;
198 }
199
200 const char *yaz_record_render(Z_NamePlusRecord *npr, const char *schema,
201                               WRBUF wrbuf,
202                               const char *type_spec, int *len)
203 {
204     size_t i;
205     char type[40];
206     char charset[40];
207     char format[3];
208     const char *cp = type_spec;
209
210     for (i = 0; cp[i] && cp[i] != ';' && cp[i] != ' ' && i < sizeof(type)-1;
211          i++)
212         type[i] = cp[i];
213     type[i] = '\0';
214     charset[0] = '\0';
215     format[0] = '\0';
216     while (1)
217     {
218         while (cp[i] == ' ')
219             i++;
220         if (cp[i] != ';')
221             break;
222         i++;
223         while (cp[i] == ' ')
224             i++;
225         if (!strncmp(cp + i, "charset=", 8))
226         {
227             size_t j = 0;
228             i = i + 8; /* skip charset= */
229             for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
230             {
231                 if (j < sizeof(charset)-1)
232                     charset[j++] = cp[i];
233             }
234             charset[j] = '\0';
235         }
236         else if (!strncmp(cp + i, "format=", 7))
237         {
238             size_t j = 0; 
239             i = i + 7;
240             for (j = 0; cp[i] && cp[i] != ';' && cp[i] != ' '; i++)
241             {
242                 if (j < sizeof(format)-1)
243                     format[j++] = cp[i];
244             }
245             format[j] = '\0';
246         } 
247     }
248     if (!strcmp(type, "database"))
249     {
250         if (len)
251             *len = (npr->databaseName ? strlen(npr->databaseName) : 0);
252         return npr->databaseName;
253     }
254     else if (!strcmp(type, "schema"))
255     {
256         if (len)
257             *len = schema ? strlen(schema) : 0;
258         return schema;
259     }
260     else if (!strcmp(type, "syntax"))
261     {
262         const char *desc = 0;   
263         if (npr->which == Z_NamePlusRecord_databaseRecord)
264         {
265             Z_External *r = (Z_External *) npr->u.databaseRecord;
266             desc = yaz_oid_to_string(yaz_oid_std(), r->direct_reference, 0);
267         }
268         if (!desc)
269             desc = "none";
270         if (len)
271             *len = strlen(desc);
272         return desc;
273     }
274     if (npr->which != Z_NamePlusRecord_databaseRecord)
275         return 0;
276
277     /* from now on - we have a database record .. */
278     if (!strcmp(type, "render"))
279     {
280         return get_record_format(wrbuf, len, npr, YAZ_MARC_LINE, charset, format);
281     }
282     else if (!strcmp(type, "xml"))
283     {
284         return get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
285                                  format);
286     }
287     else if (!strcmp(type, "txml"))
288     {
289         return get_record_format(wrbuf, len, npr, YAZ_MARC_TURBOMARC, charset,
290                                  format);
291     }
292     else if (!strcmp(type, "raw"))
293     {
294         return get_record_format(wrbuf, len, npr, YAZ_MARC_ISO2709, charset,
295             format);
296     }
297     else if (!strcmp(type, "ext"))
298     {
299         if (len) *len = -1;
300         return (const char *) npr->u.databaseRecord;
301     }
302     else if (!strcmp(type, "opac"))
303     {
304         if (npr->u.databaseRecord->which == Z_External_OPAC)
305             return get_record_format(wrbuf, len, npr, YAZ_MARC_MARCXML, charset,
306                                      format);
307     }
308     return 0;
309 }
310
311 /*
312  * Local variables:
313  * c-basic-offset: 4
314  * c-file-style: "Stroustrup"
315  * indent-tabs-mode: nil
316  * End:
317  * vim: shiftwidth=4 tabstop=8 expandtab
318  */
319