]> mj.ucw.cz Git - libucw.git/blob - charset/stk-charconv.c
2d5c206636feea3fa7e34bb6afe80f99db53eff0
[libucw.git] / charset / stk-charconv.c
1 /*
2  *      Sherlock Library -- Character Conversion with Allocation on the Stack 
3  *
4  *      (c) 2006 Pavel Charvat <pchar@ucw.cz>
5  */
6
7 #include "lib/lib.h"
8 #include "charset/stk-charconv.h"
9 #include <string.h>
10
11 #define INITIAL_MIN_SIZE        16
12 #define INITIAL_SCALE           2
13
14 void
15 stk_conv_init(struct stk_conv_context *c, byte *s, uns in_cs, uns out_cs)
16 {
17   uns l = strlen(s);
18   c->count = 0;
19
20   /* For in_cs == out_cs, we emulate stk_strdup */
21   if (in_cs == out_cs)
22   {
23     c->size[0] = c->request = l + 1;
24     c->buf[0] = s;
25     c->c.source = NULL;
26     return;
27   }
28  
29   /* Initialization */
30   conv_init(&c->c);
31   conv_set_charset(&c->c, in_cs, out_cs);
32   c->c.source = s;
33   c->c.source_end = s + l + 1;
34   c->sum = 0;
35
36   /* Size of the first buffer */
37   if (l < (INITIAL_MIN_SIZE - 1) / INITIAL_SCALE)
38     c->request = INITIAL_MIN_SIZE;
39   else
40     c->request = l * INITIAL_SCALE + 1;
41 }
42
43 int
44 stk_conv_step(struct stk_conv_context *c, byte *buf)
45 {
46   /* Merge all buffers to the new one and exit */
47   if (!c->c.source)
48   {
49     c->c.dest_start = buf;
50     for (uns i = 0; i <= c->count; i++)
51     {
52       memcpy(buf, c->buf[i], c->size[i]);
53       buf += c->size[i];
54     }  
55     return 0;
56   }
57   
58   /* Run conv_run using the new buffer */
59   c->buf[c->count] = c->c.dest_start = c->c.dest = buf;
60   c->c.dest_end = buf + c->request;
61   if (!(conv_run(&c->c) & CONV_SOURCE_END))
62   {
63
64     /* Buffer is too small, continue with a new one */
65     c->size[c->count++] = c->request;
66     c->sum += c->request;
67     c->request <<= 1; /* This can be freely changed */
68     return 1;
69   }
70
71   /* We have used only one buffer for the conversion, no merges are needed */
72   if (!c->count)
73     return 0;
74   
75   /* We can merge everything to the current buffer ... */
76   uns s = c->c.dest - c->c.dest_start;
77   if (c->sum + s <= c->request)
78   {
79     memmove(buf + c->sum, buf, s);
80     for (uns i = 0; i < c->count; i++)
81     {
82       memcpy(buf, c->buf[i], c->size[i]);
83       buf += c->size[i];
84     }
85     return 0;
86   }
87   
88   /* ... or we allocate a new one */
89   else
90   {
91     c->request = c->sum + s;
92     c->size[c->count] = s;
93     c->c.source = NULL;
94     return 1;
95   }
96 }
97