1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2009 Index Data
3 * See the file LICENSE for details.
7 * \brief MARC-8 decoding
10 * http://www.loc.gov/marc/specifications/speccharmarc8.html
22 #include <yaz/xmalloc.h>
31 unsigned long comb_x[8];
32 size_t comb_no_read[8];
35 yaz_conv_func_t yaz_marc8_42_conv;
36 yaz_conv_func_t yaz_marc8_45_conv;
37 yaz_conv_func_t yaz_marc8_67_conv;
38 yaz_conv_func_t yaz_marc8_62_conv;
39 yaz_conv_func_t yaz_marc8_70_conv;
40 yaz_conv_func_t yaz_marc8_32_conv;
41 yaz_conv_func_t yaz_marc8_4E_conv;
42 yaz_conv_func_t yaz_marc8_51_conv;
43 yaz_conv_func_t yaz_marc8_33_conv;
44 yaz_conv_func_t yaz_marc8_34_conv;
45 yaz_conv_func_t yaz_marc8_53_conv;
46 yaz_conv_func_t yaz_marc8_31_conv;
49 static unsigned long yaz_read_marc8_comb(yaz_iconv_t cd,
50 struct decoder_data *data,
52 size_t inbytesleft, size_t *no_read,
55 static unsigned long read_marc8(yaz_iconv_t cd, yaz_iconv_decoder_t d,
57 size_t inbytesleft, size_t *no_read)
59 struct decoder_data *data = (struct decoder_data *) d->data;
61 if (data->comb_offset < data->comb_size)
63 *no_read = data->comb_no_read[data->comb_offset];
64 x = data->comb_x[data->comb_offset];
66 /* special case for double-diacritic combining characters,
67 INVERTED BREVE and DOUBLE TILDE.
68 We'll increment the no_read counter by 1, since we want to skip over
69 the processing of the closing ligature character
71 /* this code is no longer necessary.. our handlers code in
72 yaz_marc8_?_conv (generated by charconv.tcl) now returns
73 0 and no_read=1 when a sequence does not match the input.
74 The SECOND HALFs in codetables.xml produces a non-existant
75 entry in the conversion trie.. Hence when met, the input byte is
76 skipped as it should (in yaz_iconv)
79 if (x == 0x0361 || x == 0x0360)
86 data->comb_offset = 0;
87 for (data->comb_size = 0; data->comb_size < 8; data->comb_size++)
91 if (inbytesleft == 0 && data->comb_size)
93 yaz_iconv_set_errno(cd, YAZ_ICONV_EINVAL);
98 x = yaz_read_marc8_comb(cd, data, inp, inbytesleft, no_read, &comb);
101 data->comb_x[data->comb_size] = x;
102 data->comb_no_read[data->comb_size] = *no_read;
104 inbytesleft = inbytesleft - *no_read;
109 static unsigned long read_marc8s(yaz_iconv_t cd, yaz_iconv_decoder_t d,
111 size_t inbytesleft, size_t *no_read)
113 struct decoder_data *data = (struct decoder_data *) d->data;
114 unsigned long x = read_marc8(cd, d, inp, inbytesleft, no_read);
115 if (x && data->comb_size == 1)
117 if (yaz_iso_8859_1_lookup_x12(x, data->comb_x[0], &x))
119 *no_read += data->comb_no_read[0];
126 static unsigned long yaz_read_marc8_comb(yaz_iconv_t cd,
127 struct decoder_data *data,
129 size_t inbytesleft, size_t *no_read,
133 while (inbytesleft > 0 && *inp == 27)
135 int *modep = &data->g0_mode;
136 size_t inbytesleft0 = inbytesleft;
140 if (inbytesleft == 0)
142 if (*inp == '$') /* set with multiple bytes */
147 if (inbytesleft == 0)
149 if (*inp == '(' || *inp == ',') /* G0 */
154 else if (*inp == ')' || *inp == '-') /* G1 */
158 modep = &data->g1_mode;
160 if (inbytesleft == 0)
162 if (*inp == '!') /* ANSEL is a special case */
167 if (inbytesleft == 0)
169 *modep = *inp++; /* Final character */
172 (*no_read) += inbytesleft0 - inbytesleft;
174 if (inbytesleft == 0)
176 else if (*inp == ' ')
184 size_t no_read_sub = 0;
185 int mode = *inp < 128 ? data->g0_mode : data->g1_mode;
190 case 'B': /* Basic ASCII */
191 case 's': /* ASCII */
192 x = yaz_marc8_42_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
194 case 'E': /* ANSEL */
195 x = yaz_marc8_45_conv(inp, inbytesleft, &no_read_sub, comb, 127, 128);
197 case 'g': /* Greek */
198 x = yaz_marc8_67_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
200 case 'b': /* Subscripts */
201 x = yaz_marc8_62_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
203 case 'p': /* Superscripts */
204 x = yaz_marc8_70_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
206 case '2': /* Basic Hebrew */
207 x = yaz_marc8_32_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
209 case 'N': /* Basic Cyrillic */
210 x = yaz_marc8_4E_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
212 case 'Q': /* Extended Cyrillic */
213 x = yaz_marc8_51_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
215 case '3': /* Basic Arabic */
216 x = yaz_marc8_33_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
218 case '4': /* Extended Arabic */
219 x = yaz_marc8_34_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
221 case 'S': /* Greek */
222 x = yaz_marc8_53_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
224 case '1': /* Chinese, Japanese, Korean (EACC) */
225 x = yaz_marc8_31_conv(inp, inbytesleft, &no_read_sub, comb, 127, 0);
229 yaz_iconv_set_errno(cd, YAZ_ICONV_EILSEQ);
232 *no_read += no_read_sub;
237 yaz_iconv_set_errno(cd, YAZ_ICONV_EINVAL);
242 static size_t init_marc8(yaz_iconv_t cd, yaz_iconv_decoder_t d,
244 size_t inbytesleft, size_t *no_read)
246 struct decoder_data *data = (struct decoder_data *) d->data;
249 data->comb_offset = data->comb_size = 0;
253 void destroy_marc8(yaz_iconv_decoder_t d)
255 struct decoder_data *data = (struct decoder_data *) d->data;
259 yaz_iconv_decoder_t yaz_marc8_decoder(const char *fromcode,
260 yaz_iconv_decoder_t d)
262 if (!yaz_matchstr(fromcode, "MARC8") || !yaz_matchstr(fromcode, "ANSEL"))
263 d->read_handle = read_marc8;
264 else if (!yaz_matchstr(fromcode, "MARC8s"))
265 d->read_handle = read_marc8s;
269 struct decoder_data *data = (struct decoder_data *)
270 xmalloc(sizeof(*data));
272 d->init_handle = init_marc8;
273 d->destroy_handle = destroy_marc8;
282 * c-file-style: "Stroustrup"
283 * indent-tabs-mode: nil
285 * vim: shiftwidth=4 tabstop=8 expandtab