summaryrefslogtreecommitdiff
path: root/uconv.c
blob: 94fd8120251b6d1172e8fb24ce2bc051bd11f552 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <stdio.h>
#include <stdlib.h>
#include <uniconv.h>
#include <assert.h>

#define UCONV_BUFSZ 4096
int main(int argc, char **argv)
{
    FILE *infp, *outfp;
    const char *from, *to;
    char inbuffer[UCONV_BUFSZ + 8];
    char outbuffer[UCONV_BUFSZ * 6];
    size_t inlen;
    uniconv_t *conv;
    size_t off;

    if (argc < 5)
	return -1;

    from = argv[1];
    to = argv[2];
    infp = fopen(argv[3], "rb");
    if (!infp)
	return -1;
    outfp = fopen(argv[4], "wb");
    if (!outfp)
	return -1;

    conv = uniconv_open(from, to);
    if (!conv)
	return -1;

    off = 0;
    while (!feof(infp)) {
	int ret;
	char *inp;
	char *outp;
	size_t len;

	len = inlen = fread(inbuffer, 1, UCONV_BUFSZ, infp);
	while (1) {
	    inp = inbuffer;
	    outp = outbuffer;
	    ret = uniconv_conv(conv, (const char **)&inp, inlen, &outp, sizeof(outbuffer));
	    if (ret == UNICONV_E2BIG && inlen < sizeof(inbuffer)) {
		size_t extralen = fread(inbuffer + inlen, 1, 1, infp);
		if (!extralen)
		    break;
		len += extralen;
		inlen += extralen;
		continue;
	    }
	    if (ret) {
		printf ("Failed to convert.\n");
		exit(-1);
		break;
	    }
	    assert (inp - inbuffer == inlen);
	    fwrite(outbuffer, 1, outp - outbuffer, outfp);
	    break;
	}
	off += len;
    }

    fclose(outfp);
    fclose(infp);

    uniconv_close(conv);

    return 0;
}