summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/dietlibc/libugly/iconv.c
blob: 45be5d91dea37104a31eab93ca8b61e76890af77 (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 "dietfeatures.h"
#include <errno.h>
#include "dieticonv.h"
#include <netinet/in.h>

size_t iconv(iconv_t cd, const char* * inbuf, size_t *
		    inbytesleft, char* * outbuf, size_t * outbytesleft) {
  size_t converted=0,i,j,k;
  int bits;
  if (!inbuf || !*inbuf) return 0;
  while (*inbytesleft) {
    unsigned int v=0;
    v=*(unsigned char*)*inbuf;
    i=j=1;
    switch (ic_from(cd)) {
    case UCS_2:
      v=ntohs(*(unsigned short*)*inbuf);
      i=2;
      break;
    case UCS_4:
      v=ntohs(*(unsigned int*)*inbuf);
      i=4;
    case ISO_8859_1:
      break;
    case UTF_8:
      if (!(v&0x80)) break;
      for (i=0xC0; i!=0xFC; i=(i>>1)+0x80)
	if ((v&((i>>1)|0x80))==i) {
	  v&=~i;
	  break;
	}
      for (i=1; ((*inbuf)[i]&0xc0)==0x80; ++i)
	v=(v<<6)|((*inbuf)[i]&0x3f);
/*      printf("got %u in %u bytes, buflen %u\n",v,i,*inbytesleft); */
      break;
    }
    switch (ic_to(cd)) {
    case ISO_8859_1:
      **outbuf=(unsigned char)v;
      break;
    case UCS_2:
      *(unsigned short*)*outbuf=htons(v);
      j=2;
      break;
    case UCS_4:
      *(unsigned int*)*outbuf=htonl(v);
      j=4;
      break;
    case UTF_8:
      if (v>0x04000000) { bits=30; **outbuf=0xFC; j=6; } else
      if (v>0x00200000) { bits=24; **outbuf=0xF8; j=5; } else
      if (v>0x00010000) { bits=18; **outbuf=0xF0; j=4; } else
      if (v>0x00000800) { bits=12; **outbuf=0xE0; j=3; } else
      if (v>0x00000080) { bits=6; **outbuf=0xC0; j=2; } else
			{ bits=0; **outbuf=0; }
      **outbuf |= (unsigned char)(v>>bits);
      if (*outbytesleft<j) {
	errno=E2BIG;
	return (size_t)-1;
      }
      for (k=1; k<j; ++k) {
	bits-=6;
	(*outbuf)[k]=0x80+((v>>bits)&0x3F);
      }
      break;
    }
    *inbuf+=i; *inbytesleft-=i; ++converted;
    *outbuf+=j; *outbytesleft-=j;
  }
  return converted;
}