1/*
2 * libid3tag - ID3 tag manipulation library
3 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 *
19 * $Id: ucs4.c,v 1.13 2004/01/23 09:41:32 rob Exp $
20 */
21
22# ifdef HAVE_CONFIG_H
23#  include "config.h"
24# endif
25
26# include "global.h"
27
28# include <stdlib.h>
29
30# include "id3tag.h"
31# include "ucs4.h"
32# include "latin1.h"
33# include "utf16.h"
34# include "utf8.h"
35
36id3_ucs4_t const id3_ucs4_empty[] = { 0 };
37
38/*
39 * NAME:	ucs4->length()
40 * DESCRIPTION:	return the number of ucs4 chars represented by a ucs4 string
41 */
42id3_length_t id3_ucs4_length(id3_ucs4_t const *ucs4)
43{
44  id3_ucs4_t const *ptr = ucs4;
45
46  while (*ptr)
47    ++ptr;
48
49  return ptr - ucs4;
50}
51
52/*
53 * NAME:	ucs4->size()
54 * DESCRIPTION:	return the encoding size of a ucs4 string
55 */
56id3_length_t id3_ucs4_size(id3_ucs4_t const *ucs4)
57{
58  return id3_ucs4_length(ucs4) + 1;
59}
60
61/*
62 * NAME:	ucs4->latin1size()
63 * DESCRIPTION:	return the encoding size of a latin1-encoded ucs4 string
64 */
65id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *ucs4)
66{
67  return id3_ucs4_size(ucs4);
68}
69
70/*
71 * NAME:	ucs4->utf16size()
72 * DESCRIPTION:	return the encoding size of a utf16-encoded ucs4 string
73 */
74id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *ucs4)
75{
76  id3_length_t size = 0;
77
78  while (*ucs4) {
79    ++size;
80    if (*ucs4 >= 0x00010000L &&
81	*ucs4 <= 0x0010ffffL)
82      ++size;
83
84    ++ucs4;
85  }
86
87  return size + 1;
88}
89
90/*
91 * NAME:	ucs4->utf8size()
92 * DESCRIPTION:	return the encoding size of a utf8-encoded ucs4 string
93 */
94id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *ucs4)
95{
96  id3_length_t size = 0;
97
98  while (*ucs4) {
99    if (*ucs4 <= 0x0000007fL)
100      size += 1;
101    else if (*ucs4 <= 0x000007ffL)
102      size += 2;
103    else if (*ucs4 <= 0x0000ffffL)
104      size += 3;
105    else if (*ucs4 <= 0x001fffffL)
106      size += 4;
107    else if (*ucs4 <= 0x03ffffffL)
108      size += 5;
109    else if (*ucs4 <= 0x7fffffffL)
110      size += 6;
111    else
112      size += 2;  /* based on U+00B7 replacement char */
113
114    ++ucs4;
115  }
116
117  return size + 1;
118}
119
120/*
121 * NAME:	ucs4->latin1duplicate()
122 * DESCRIPTION:	duplicate and encode a ucs4 string into latin1
123 */
124id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *ucs4)
125{
126  id3_latin1_t *latin1;
127
128  latin1 = malloc(id3_ucs4_latin1size(ucs4) * sizeof(*latin1));
129  if (latin1)
130    id3_latin1_encode(latin1, ucs4);
131
132  return release(latin1);
133}
134
135/*
136 * NAME:	ucs4->utf16duplicate()
137 * DESCRIPTION:	duplicate and encode a ucs4 string into utf16
138 */
139id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *ucs4)
140{
141  id3_utf16_t *utf16;
142
143  utf16 = malloc(id3_ucs4_utf16size(ucs4) * sizeof(*utf16));
144  if (utf16)
145    id3_utf16_encode(utf16, ucs4);
146
147  return release(utf16);
148}
149
150/*
151 * NAME:	ucs4->utf8duplicate()
152 * DESCRIPTION:	duplicate and encode a ucs4 string into utf8
153 */
154id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *ucs4)
155{
156  id3_utf8_t *utf8;
157
158  utf8 = malloc(id3_ucs4_utf8size(ucs4) * sizeof(*utf8));
159  if (utf8)
160    id3_utf8_encode(utf8, ucs4);
161
162  return release(utf8);
163}
164
165/*
166 * NAME:	ucs4->copy()
167 * DESCRIPTION:	copy a ucs4 string
168 */
169void id3_ucs4_copy(id3_ucs4_t *dest, id3_ucs4_t const *src)
170{
171  while ((*dest++ = *src++))
172    ;
173}
174
175/*
176 * NAME:	ucs4->duplicate()
177 * DESCRIPTION:	duplicate a ucs4 string
178 */
179id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *src)
180{
181  id3_ucs4_t *ucs4;
182
183  ucs4 = malloc(id3_ucs4_size(src) * sizeof(*ucs4));
184  if (ucs4)
185    id3_ucs4_copy(ucs4, src);
186
187  return ucs4;
188}
189
190/*
191 * NAME:	ucs4->putnumber()
192 * DESCRIPTION:	write a ucs4 string containing a (positive) decimal number
193 */
194void id3_ucs4_putnumber(id3_ucs4_t *ucs4, unsigned long number)
195{
196  int digits[10], *digit;
197
198  digit = digits;
199
200  do {
201    *digit++ = number % 10;
202    number  /= 10;
203  }
204  while (number);
205
206  while (digit != digits)
207    *ucs4++ = '0' + *--digit;
208
209  *ucs4 = 0;
210}
211
212/*
213 * NAME:	ucs4->getnumber()
214 * DESCRIPTION:	read a ucs4 string containing a (positive) decimal number
215 */
216unsigned long id3_ucs4_getnumber(id3_ucs4_t const *ucs4)
217{
218  unsigned long number = 0;
219
220  while (*ucs4 >= '0' && *ucs4 <= '9')
221    number = 10 * number + (*ucs4++ - '0');
222
223  return number;
224}
225