2 * Copyright (c) 2000 Adrian Sun
3 * All Rights Reserved. See COPYRIGHT.
5 * codepage support (based initially on some code from
9 * for single-byte maps, the codepage support devolves to a lookup
10 * table for all possible 8-bit values. for double-byte maps,
11 * the first byte is used as a hash index followed by a linked list of
14 * the badumap specifies illegal characters. these are 8-bit values
15 * with an associated rule field. here are the rules:
18 * illegal values: 0 is the only illegal value. no translation will
19 * occur in those cases.
25 #include <sys/types.h>
31 #include <netatalk/endian.h>
39 /* deal with linked lists */
40 #define CP_INIT(a) (a)->next = (a)->prev = (a)
41 #define CP_ADD(a, b) do { \
42 (b)->next = (a)->next; \
46 #define CP_REMOVE(a) do { \
47 (a)->prev->next = (a)->next; \
48 (a)->next->prev = (a)->prev; \
51 /* search for stuff */
53 static __inline__ unsigned char *codepage_find(struct codepage *page,
59 static int add_code(struct codepage *page, unsigned char *from,
62 union codepage_val *ptr;
64 if (page->quantum < 1) /* no quantum given. don't do anything */
67 if (page->quantum == 1) {
68 page->map[*from].value = *to;
73 if (ptr = codepage_find(page->map, from)) {
77 ptr = map[*from].hash;
79 space = (unsigned char *) malloc(sizeof(unsigned char)*quantum);
89 static struct codepage *init_codepage(const int quantum)
93 cp = (struct codepage *) malloc(sizeof(struct codepage));
97 if ((cp->map = (union codepage_val *)
98 calloc(MAPSIZE, sizeof(union codepage_val))) == NULL) {
103 cp->quantum = quantum;
108 static void free_codepage(struct codepage *cp)
116 if (cp->quantum > 1) {
117 /* deal with any linked lists that may exist */
118 for (i = 0; i < MAPSIZE; i++) {
119 struct codepage_hash *ptr, *h;
121 h = &cp->map[i].hash; /* we don't free this one */
122 while ((ptr = h->prev) != h) {
135 /* this is used by both codepages and generic mapping utilities. we
136 * allocate enough space to map all 8-bit characters if necessary.
137 * for double-byte mappings, we just use the table as a hash lookup.
138 * if we don't match, we don't convert.
140 int codepage_init(struct vol *vol, const int rules,
143 if ((rules & CODEPAGE_RULE_MTOU) && !vol->v_utompage) {
144 vol->v_utompage = init_codepage(quantum);
145 if (!vol->v_utompage)
149 if ((rules & CODEPAGE_RULE_UTOM) && !vol->v_mtoupage) {
150 vol->v_mtoupage = init_codepage(quantum);
151 if (!vol->v_mtoupage) {
156 if ((rules & CODEPAGE_RULE_BADU) && !vol->v_badumap) {
157 vol->v_badumap = init_codepage(quantum);
164 free_codepage(vol->v_mtoupage);
165 vol->v_mtoupage = NULL;
168 free_codepage(vol->v_utompage);
169 vol->v_utompage = NULL;
173 void codepage_free(struct vol *vol)
175 if (vol->v_utompage) {
176 free_codepage(vol->v_utompage);
177 vol->v_utompage = NULL;
180 if (vol->v_mtoupage) {
181 free_codepage(vol->v_mtoupage);
182 vol->v_mtoupage = NULL;
185 if (vol->v_badumap) {
186 free_codepage(vol->v_badumap);
187 vol->v_badumap = NULL;
192 int codepage_read(struct vol *vol, const char *path)
194 unsigned char buf[CODEPAGE_FILE_HEADER_SIZE], *cur;
196 int fd, i, quantum, rules;
198 if ((fd = open(path, O_RDONLY)) < 0) {
199 syslog(LOG_ERR, "%s: failed to open codepage", path);
203 /* Read the codepage file header. */
204 if(read(fd, buf, sizeof(buf)) != sizeof(buf)) {
205 syslog( LOG_ERR, "%s: failed to read codepage header", path);
209 /* Check the file id */
211 memcpy(&id, cur, sizeof(id));
214 if (id != CODEPAGE_FILE_ID) {
215 syslog( LOG_ERR, "%s: not a codepage", path);
219 /* check the version number */
220 if (*cur++ != CODEPAGE_FILE_VERSION) {
221 syslog( LOG_ERR, "%s: codepage version not supported", path);
225 /* find out the data quantum size. default to 1 if nothing's given. */
226 quantum = *cur ? *cur : 1;
229 /* rules used in this file. */
232 if (codepage_init(vol, rules, quantum) < 0) {
233 syslog( LOG_ERR, "%s: Unable to allocate memory", path);
239 /* skip to the start of the data */
240 memcpy(&id, cur , sizeof(id));
242 lseek(fd, id, SEEK_SET);
244 /* mtoupage is the the equivalent of samba's unix2dos. utompage is
245 * the equivalent of dos2unix. it's a little confusing due to a
246 * desire to match up with mtoupath and utompath.
247 * NOTE: we allow codepages to specify 7-bit mappings if they want.
250 while (read(fd, buf, i) == i) {
251 if (*buf & CODEPAGE_RULE_MTOU) {
252 if (add_code(vol->v_mtoupage, buf + 1, buf + 1 + quantum) < 0) {
253 syslog(LOG_ERR, "unable to allocate memory for mtoupage");
258 if (*buf & CODEPAGE_RULE_UTOM) {
259 if (add_code(vol->v_utompage, buf + 1 + quantum, buf + 1) < 0) {
260 syslog(LOG_ERR, "unable to allocate memory for utompage");
265 /* we only look at the first character here. if we need to
266 * do so, we can always use the quantum to expand the
267 * available flags. */
268 if (*buf & CODEPAGE_RULE_BADU)
269 vol->v_badumap->map[*(buf + 1)].value = *(buf + 1 + quantum);