YAZ  5.34.0
iconv_encode_danmarc.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
10 #if HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13 
14 #include <assert.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <string.h>
18 
19 #include <yaz/xmalloc.h>
20 #include "iconv-p.h"
21 
22 #define MAX_COMP 4
23 
25 {
26  unsigned long comp[MAX_COMP];
27  size_t sz;
28  unsigned long base_char;
29  int dia;
30 };
31 
32 static size_t write1(yaz_iconv_t cd, unsigned long x,
33  char **outbuf, size_t *outbytesleft)
34 {
35  unsigned char *outp = (unsigned char *) *outbuf;
36  if (x == '@' || x == '*')
37  {
38  if (*outbytesleft < 2)
39  {
41  return (size_t)(-1);
42  }
43  *outp++ = '@';
44  (*outbytesleft)--;
45  *outp++ = (unsigned char) x;
46  (*outbytesleft)--;
47  }
48  else if (x <= 0xff)
49  { /* latin-1 range */
50  if (*outbytesleft < 1)
51  {
53  return (size_t)(-1);
54  }
55  *outp++ = (unsigned char) x;
56  (*outbytesleft)--;
57  }
58  else if (x <= 0xffff)
59  {
60  if (*outbytesleft < 6)
61  {
63  return (size_t)(-1);
64  }
65  switch (x)
66  {
67  case 0xa733:
68  *outp++ = '@';
69  *outp++ = 0xe5;
70  (*outbytesleft) -= 2;
71  break;
72  case 0xa732:
73  *outp++ = '@';
74  *outp++ = 0xc5;
75  (*outbytesleft) -= 2;
76  break;
77  default:
78  /* full unicode, emit @XXXX */
79  sprintf(*outbuf, "@%04lX", x);
80  outp += 5;
81  (*outbytesleft) -= 5;
82  break;
83  }
84  }
85  else
86  { /* can not be encoded in Danmarc2 */
88  return (size_t)(-1);
89  }
90  *outbuf = (char *) outp;
91  return 0;
92 }
93 
95  char **outbuf, size_t *outbytesleft)
96 {
97  struct encoder_data *w = (struct encoder_data *) e->data;
98  /* see if this is a combining thing that can be mapped to Latin-1 */
99  if (w->base_char && w->sz == 1)
100  {
101  unsigned long y;
102  if (yaz_iso_8859_1_lookup_x12(w->base_char, w->comp[0], &y))
103  {
104  w->base_char = y;
105  w->sz = 0;
106  }
107  }
108  /* combining characters in reverse */
109  while (w->sz > 0)
110  {
111  unsigned long x = w->comp[w->sz - 1];
112  if (w->dia)
114  size_t r = write1(cd, x, outbuf, outbytesleft);
115  if (r)
116  return r;
117  w->sz--;
118  }
119  /* then base char */
120  if (w->base_char)
121  {
122  size_t r = write1(cd, w->base_char, outbuf, outbytesleft);
123  if (r)
124  return r; /* if we fail base_char is still there.. */
125  w->base_char = 0;
126  }
127  return 0;
128 }
129 
131  unsigned long x,
132  char **outbuf, size_t *outbytesleft)
133 {
134  struct encoder_data *w = (struct encoder_data *) e->data;
135 
136  /* check for combining characters */
138  {
139  w->comp[w->sz++] = x;
140  if (w->sz < MAX_COMP)
141  return 0;
142  }
143  /* x is NOT a combining character. Flush previous sequence */
144  size_t r = flush_danmarc(cd, e, outbuf, outbytesleft);
145  if (r)
146  return r;
147  w->base_char = x;
148  return 0;
149 }
150 
152 {
153  struct encoder_data *w = (struct encoder_data *) e->data;
154  w->base_char = 0;
155  w->sz = 0;
156 }
157 
159 {
160  xfree(e->data);
161 }
162 
165 
166 {
167  if (!yaz_matchstr(tocode, "danmarc"))
168  {
169  struct encoder_data *data = (struct encoder_data *)
170  xmalloc(sizeof(*data));
171  data->dia = 0;
172  e->data = data;
177  return e;
178  }
179  if (!yaz_matchstr(tocode, "danmarc2"))
180  {
181  struct encoder_data *data = (struct encoder_data *)
182  xmalloc(sizeof(*data));
183  data->dia = 1;
184  e->data = data;
189  return e;
190  }
191  return 0;
192 }
193 
194 /*
195  * Local variables:
196  * c-basic-offset: 4
197  * c-file-style: "Stroustrup"
198  * indent-tabs-mode: nil
199  * End:
200  * vim: shiftwidth=4 tabstop=8 expandtab
201  */
202 
Header for errno utilities.
Internal header for iconv.
int yaz_iso_8859_1_lookup_x12(unsigned long x1, unsigned long x2, unsigned long *y)
int yaz_danmarc_is_combining(unsigned long ch)
unsigned long yaz_danmarc_swap_to_danmarc(unsigned long ch)
void yaz_iconv_set_errno(yaz_iconv_t cd, int no)
Definition: siconv.c:298
static size_t write_danmarc(yaz_iconv_t cd, yaz_iconv_encoder_t e, unsigned long x, char **outbuf, size_t *outbytesleft)
static void init_danmarc(yaz_iconv_encoder_t e)
yaz_iconv_encoder_t yaz_danmarc_encoder(const char *tocode, yaz_iconv_encoder_t e)
static size_t flush_danmarc(yaz_iconv_t cd, yaz_iconv_encoder_t e, char **outbuf, size_t *outbytesleft)
static size_t write1(yaz_iconv_t cd, unsigned long x, char **outbuf, size_t *outbytesleft)
#define MAX_COMP
static void destroy_danmarc(yaz_iconv_encoder_t e)
unsigned y
int yaz_matchstr(const char *s1, const char *s2)
match strings - independent of case and '-'
Definition: matchstr.c:42
unsigned long comp[MAX_COMP]
unsigned long base_char
void(* init_handle)(yaz_iconv_encoder_t e)
Definition: iconv-p.h:50
size_t(* write_handle)(yaz_iconv_t cd, yaz_iconv_encoder_t e, unsigned long x, char **outbuf, size_t *outbytesleft)
Definition: iconv-p.h:45
void(* destroy_handle)(yaz_iconv_encoder_t e)
Definition: iconv-p.h:51
size_t(* flush_handle)(yaz_iconv_t cd, yaz_iconv_encoder_t e, char **outbuf, size_t *outbytesleft)
Definition: iconv-p.h:48
Header for memory handling functions.
#define xfree(x)
utility macro which calls xfree_f
Definition: xmalloc.h:53
#define xmalloc(x)
utility macro which calls malloc_f
Definition: xmalloc.h:49
#define YAZ_ICONV_EILSEQ
error code: Invalid sequence
Definition: yaz-iconv.h:49
#define YAZ_ICONV_E2BIG
error code: Not sufficient room for output buffer
Definition: yaz-iconv.h:47