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