c14a404ccff58d773b4b347b547a2207179d95b5
[yaz-moved-to-github.git] / src / iconv_decode_danmarc.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2009 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file
7  * \brief Danmarc2 character set decoding
8  *
9  */
10
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <assert.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <stdio.h>
20 #include <yaz/log.h>
21 #include <yaz/xmalloc.h>
22 #include "iconv-p.h"
23
24 struct decoder_data {
25     unsigned long x_back;
26 };
27
28 static unsigned long read_danmarc(yaz_iconv_t cd, 
29                                   yaz_iconv_decoder_t d,
30                                   unsigned char *inp,
31                                   size_t inbytesleft, size_t *no_read)
32 {
33     struct decoder_data *data = (struct decoder_data *) d->data;
34     unsigned long x = inp[0];
35
36     if (data->x_back)
37     {
38         *no_read = 1;
39         x = data->x_back;
40         data->x_back = 0;
41         return x;
42     }
43
44     if (x == '@')
45     {
46         if (inbytesleft < 2)
47         {
48             yaz_iconv_set_errno(cd, YAZ_ICONV_EINVAL);
49             *no_read = 0;
50             return 0;
51         }
52         switch(inp[1])
53         {
54         case '@':
55         case '*':
56         case 0xa4: /* CURRENCY SIGN */
57             x = inp[1];
58             *no_read = 2;
59             break;
60         case 0xe5: /* LATIN SMALL LETTER A WITH RING ABOVE */
61             x = 'a';
62             data->x_back = 'a';
63             *no_read = 1;
64             break;
65         case 0xc5: /* LATIN CAPITAL LETTER A WITH RING ABOVE */
66             x = 'A';
67             data->x_back = 'a';
68             *no_read = 1;
69             break;
70         default:
71             if (inbytesleft < 5)
72             {
73                 yaz_iconv_set_errno(cd, YAZ_ICONV_EINVAL);
74                 *no_read = 0;
75                 return 0;
76             }
77             else
78             {
79                 unsigned long v;
80                 sscanf((const char *) inp+1, "%4lx", &v);
81                 *no_read = 5;
82                 x = v;
83             }
84         }
85     }
86     else
87         *no_read = 1;
88     return x;
89 }
90
91
92 static size_t init_danmarc(yaz_iconv_t cd, yaz_iconv_decoder_t d,
93                            unsigned char *inp,
94                            size_t inbytesleft, size_t *no_read)
95 {
96     struct decoder_data *data = (struct decoder_data *) d->data;
97     data->x_back = 0;
98     return 0;
99 }
100
101 void destroy_danmarc(yaz_iconv_decoder_t d)
102 {
103     struct decoder_data *data = (struct decoder_data *) d->data;
104     xfree(data);
105 }
106
107 yaz_iconv_decoder_t yaz_danmarc_decoder(const char *fromcode,
108                                         yaz_iconv_decoder_t d)
109     
110 {
111     if (!yaz_matchstr(fromcode, "danmarc"))
112     {
113         struct decoder_data *data = (struct decoder_data *)
114             xmalloc(sizeof(*data));
115         d->data = data;
116         data->x_back = 0;
117         d->read_handle = read_danmarc;
118         d->init_handle = init_danmarc;
119         d->destroy_handle = destroy_danmarc;
120         return d;
121     }
122     return 0;
123 }
124
125
126 /*
127  * Local variables:
128  * c-basic-offset: 4
129  * c-file-style: "Stroustrup"
130  * indent-tabs-mode: nil
131  * End:
132  * vim: shiftwidth=4 tabstop=8 expandtab
133  */
134