2 * $Id: codepage.c,v 1.8 2002-03-24 01:23:40 sibaz Exp $
4 * Copyright (c) 2000 Adrian Sun
5 * All Rights Reserved. See COPYRIGHT.
7 * codepage support (based initially on some code from
11 * for single-byte maps, the codepage support devolves to a lookup
12 * table for all possible 8-bit values. for double-byte maps,
13 * the first byte is used as a hash index followed by a linked list of
16 * the badumap specifies illegal characters. these are 8-bit values
17 * with an associated rule field. here are the rules:
19 * illegal values: 0 is the only illegal value. no translation will
20 * occur in those cases.
25 #endif /* HAVE_CONFIG_H */
30 #include <sys/types.h>
34 #endif /* HAVE_FCNTL_H */
37 #endif /* HAVE_UNISTD_H */
38 #include <atalk/logger.h>
40 #include <netatalk/endian.h>
48 /* deal with linked lists */
49 #define CP_INIT(a) (a)->next = (a)->prev = (a)
50 #define CP_ADD(a, b) do { \
51 (b)->next = (a)->next; \
55 #define CP_REMOVE(a) do { \
56 (a)->prev->next = (a)->next; \
57 (a)->next->prev = (a)->prev; \
60 /* search for stuff */
62 static __inline__ unsigned char *codepage_find(struct codepage *page,
68 static int add_code(struct codepage *page, unsigned char *from,
72 union codepage_val *ptr;
75 if (page->quantum < 1) /* no quantum given. don't do anything */
78 if (page->quantum == 1) {
79 page->map[*from].value = *to;
84 if (ptr = codepage_find(page->map, from)) {
88 ptr = map[*from].hash;
90 space = (unsigned char *) malloc(sizeof(unsigned char)*quantum);
101 static struct codepage *init_codepage(const int quantum)
105 cp = (struct codepage *) malloc(sizeof(struct codepage));
109 if ((cp->map = (union codepage_val *)
110 calloc(MAPSIZE, sizeof(union codepage_val))) == NULL) {
115 cp->quantum = quantum;
120 static void free_codepage(struct codepage *cp)
128 if (cp->quantum > 1) {
129 /* deal with any linked lists that may exist */
130 for (i = 0; i < MAPSIZE; i++) {
131 struct codepage_hash *ptr, *h;
133 h = &cp->map[i].hash; /* we don't free this one */
134 while ((ptr = h->prev) != h) {
147 /* this is used by both codepages and generic mapping utilities. we
148 * allocate enough space to map all 8-bit characters if necessary.
149 * for double-byte mappings, we just use the table as a hash lookup.
150 * if we don't match, we don't convert.
152 int codepage_init(struct vol *vol, const int rules,
155 if ((rules & CODEPAGE_RULE_UTOM) && !vol->v_utompage) {
156 vol->v_utompage = init_codepage(quantum);
157 if (!vol->v_utompage)
161 if ((rules & CODEPAGE_RULE_MTOU) && !vol->v_mtoupage) {
162 vol->v_mtoupage = init_codepage(quantum);
163 if (!vol->v_mtoupage) {
168 if ((rules & CODEPAGE_RULE_BADU) && !vol->v_badumap) {
169 vol->v_badumap = init_codepage(quantum);
176 free_codepage(vol->v_mtoupage);
177 vol->v_mtoupage = NULL;
180 free_codepage(vol->v_utompage);
181 vol->v_utompage = NULL;
185 void codepage_free(struct vol *vol)
187 if (vol->v_utompage) {
188 free_codepage(vol->v_utompage);
189 vol->v_utompage = NULL;
192 if (vol->v_mtoupage) {
193 free_codepage(vol->v_mtoupage);
194 vol->v_mtoupage = NULL;
197 if (vol->v_badumap) {
198 free_codepage(vol->v_badumap);
199 vol->v_badumap = NULL;
204 int codepage_read(struct vol *vol, const char *path)
206 unsigned char buf[CODEPAGE_FILE_HEADER_SIZE], *cur;
208 int fd, i, quantum, rules;
210 if ((fd = open(path, O_RDONLY)) < 0) {
211 LOG(log_error, logtype_afpd, "%s: failed to open codepage", path);
215 /* Read the codepage file header. */
216 if(read(fd, buf, sizeof(buf)) != sizeof(buf)) {
217 LOG(log_error, logtype_afpd, "%s: failed to read codepage header", path);
221 /* Check the file id */
223 memcpy(&id, cur, sizeof(id));
226 if (id != CODEPAGE_FILE_ID) {
227 LOG(log_error, logtype_afpd, "%s: not a codepage", path);
231 /* check the version number */
232 if (*cur++ != CODEPAGE_FILE_VERSION) {
233 LOG(log_error, logtype_afpd, "%s: codepage version not supported", path);
240 /* find out the data quantum size. default to 1 if nothing's given. */
241 quantum = *cur ? *cur : 1;
244 /* rules used in this file. */
247 if (codepage_init(vol, rules, quantum) < 0) {
248 LOG(log_error, logtype_afpd, "%s: Unable to allocate memory", path);
254 /* skip to the start of the data */
255 memcpy(&id, cur , sizeof(id));
257 lseek(fd, id, SEEK_SET);
259 /* mtoupage is the the equivalent of samba's unix2dos. utompage is
260 * the equivalent of dos2unix. it's a little confusing due to a
261 * desire to match up with mtoupath and utompath.
262 * NOTE: we allow codepages to specify 7-bit mappings if they want.
265 while (read(fd, buf, i) == i) {
266 if (*buf & CODEPAGE_RULE_MTOU) {
267 if (add_code(vol->v_mtoupage, buf + 1, buf + 1 + quantum) < 0) {
268 LOG(log_error, logtype_afpd, "unable to allocate memory for mtoupage");
273 if (*buf & CODEPAGE_RULE_UTOM) {
274 if (add_code(vol->v_utompage, buf + 1 + quantum, buf + 1) < 0) {
275 LOG(log_error, logtype_afpd, "unable to allocate memory for utompage");
280 /* we only look at the first character here. if we need to
281 * do so, we can always use the quantum to expand the
282 * available flags. */
283 if (*buf & CODEPAGE_RULE_BADU)
284 vol->v_badumap->map[*(buf + 1)].value = *(buf + 1 + quantum);