1 /*
2   LibRCC - module handling internal string representation
3 
4   Copyright (C) 2005-2008 Suren A. Chilingaryan <csa@dside.dyndns.org>
5 
6   This library is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License version 2.1 or later
8   as published by the Free Software Foundation.
9 
10   This library is distributed in the hope that it will be useful, but WITHOUT
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
13   for more details.
14 
15   You should have received a copy of the GNU Lesser General Public License
16   along with this program; if not, write to the Free Software Foundation, Inc.,
17   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #include <string.h>
24 #ifdef HAVE_STRINGS_H
25 # include <strings.h>
26 #endif /* HAVE_STRINGS_H */
27 
28 #include "../config.h"
29 
30 #include "internal.h"
31 #include "rccstring.h"
32 
rccCreateString(rcc_language_id language_id,const char * buf,size_t len)33 rcc_string rccCreateString(rcc_language_id language_id, const char *buf, size_t len) {
34     char *res;
35     rcc_string_header *header;
36 
37     if (!buf) return NULL;
38     if (!len) len = strlen(buf);
39 
40     res = (char*)malloc(len+sizeof(rcc_string_header)+1);
41     if (!res) return NULL;
42 
43     memcpy(res + sizeof(rcc_string_header), buf, len);
44     res[sizeof(rcc_string_header) + len] = 0;
45 
46     memset(res, 0xFF, sizeof(rcc_string_header));
47     header = (rcc_string_header*)res;
48     header->magic = RCC_STRING_MAGIC;
49     header->language_id = language_id;
50 
51     return (rcc_string)res;
52 }
53 
rccStringSetLang(rcc_string string,const char * sn)54 int rccStringSetLang(rcc_string string, const char *sn) {
55     if ((!string)||(!sn)||(strlen(sn)!=2)) return -1;
56     memcpy(&((rcc_string_header*)string)->language,sn,2);
57     return 0;
58 }
59 
rccStringFixID(rcc_string string,rcc_context ctx)60 int rccStringFixID(rcc_string string, rcc_context ctx) {
61     char lang[3];
62     const char *curlang;
63     rcc_language_config config;
64     rcc_language_id language_id;
65     rcc_string_header *header;
66 
67     if ((!string)||(!ctx)||(!rccStringCheck(string))) return -1;
68     header = (rcc_string_header*)string;
69 
70 
71     memcpy(lang, header->language, 2); lang[2] = 0;
72     curlang = rccGetLanguageName(ctx, header->language_id);
73     if ((curlang)&&(!strcasecmp(lang, curlang))) return 0;
74 
75     language_id = rccGetLanguageByName(ctx, lang);
76     if ((language_id == (rcc_language_id)-1)||(language_id == 0)) return -1;
77     config = rccGetConfig(ctx, language_id);
78     if (!config) return -1;
79 
80     header->language_id = language_id;
81     return 0;
82 }
83 
rccStringChangeID(rcc_string string,rcc_language_id language_id)84 int rccStringChangeID(rcc_string string, rcc_language_id language_id) {
85     if ((!string)&&(language_id != (rcc_language_id)-1)) return -1;
86 
87 //    printf("ChangingID %lu: %s\n", language_id, string);
88     ((rcc_string_header*)string)->language_id = language_id;
89     return 0;
90 }
91 
92 
rccStringFree(rcc_string str)93 void rccStringFree(rcc_string str) {
94     if (str) free(str);
95 }
96 
rccStringCheck(const char * str)97 size_t rccStringCheck(const char *str) {
98     size_t len;
99 
100     if (!str) return 0;
101 
102     len = strlen(str);
103     if (len>sizeof(rcc_string_header)) {
104 	len-=sizeof(rcc_string_header);
105         if (((rcc_string_header*)str)->magic == RCC_STRING_MAGIC) return len;
106     }
107 
108     return 0;
109 }
110 
rccStringSizedCheck(const char * str,size_t len)111 size_t rccStringSizedCheck(const char *str, size_t len) {
112     size_t newlen;
113 
114     if (!str) return 0;
115 
116     newlen = len?len:strlen(str);
117     if (newlen>sizeof(rcc_string_header)) {
118 	if ((len==newlen)&&(!str[newlen-2])) return 0;
119 	newlen-=sizeof(rcc_string_header);
120     } else return 0;
121     if (((rcc_string_header*)str)->magic == RCC_STRING_MAGIC) return newlen;
122     return 0;
123 }
124 
125 
rccStringGetLanguage(rcc_const_string str)126 rcc_language_id rccStringGetLanguage(rcc_const_string str) {
127     if (!str) return (rcc_language_id)-1;
128     return ((rcc_string_header*)str)->language_id;
129 }
130 
rccStringGetString(rcc_const_string str)131 const char *rccStringGetString(rcc_const_string str) {
132     return (const char *)str + sizeof(rcc_string_header);
133 }
134 
rccStringExtractString(rcc_const_string str)135 char *rccStringExtractString(rcc_const_string str) {
136     size_t len;
137     char *res;
138 
139     len = rccStringCheck(str);
140     if (!len) return NULL;
141 
142     res = (char*)malloc(len+1);
143     if (!res) return NULL;
144 
145     memcpy(res, rccStringGetString(str), len);
146     res[len] = 0;
147 
148     return res;
149 }
150 
151 
rccGetString(const char * str)152 const char *rccGetString(const char *str) {
153     if (rccStringCheck(str)) return rccStringGetString((const rcc_string)str);
154     return str;
155 }
156 
rccSizedGetString(const char * str,size_t len)157 const char *rccSizedGetString(const char *str, size_t len) {
158     size_t newlen;
159 
160     newlen = rccStringSizedCheck(str, len);
161     if (newlen) {
162 	return rccStringGetString((const rcc_string)str);
163     }
164 
165     return (const char *)str;
166 }
167 
168 
rccStringCmp(const char * str1,const char * str2)169 int rccStringCmp(const char *str1, const char *str2) {
170     return strcmp(rccGetString(str1), rccGetString(str2));
171 }
172 
rccStringNCmp(const char * str1,const char * str2,size_t n)173 int rccStringNCmp(const char *str1, const char *str2, size_t n) {
174     return strncmp(rccGetString(str1), rccGetString(str2), n);
175 }
176 
rccStringCaseCmp(const char * str1,const char * str2)177 int rccStringCaseCmp(const char *str1, const char *str2) {
178     return strcasecmp(rccGetString(str1), rccGetString(str2));
179 }
180 
rccStringNCaseCmp(const char * str1,const char * str2,size_t n)181 int rccStringNCaseCmp(const char *str1, const char *str2, size_t n) {
182     return strncasecmp(rccGetString(str1), rccGetString(str2), n);
183 }
184 
185 #ifndef HAVE_STRNLEN
rccStrnlen(const char * str,size_t size)186 int rccStrnlen(const char *str, size_t size) {
187     unsigned int i;
188     for (i=0;((i<size)&&(str[i]));i++);
189     return i;
190 }
191 #endif /* HAVE_STRNLEN */
192 
193 
rccIsASCII(const char * str)194 int rccIsASCII(const char *str) {
195     unsigned int i;
196 
197     for (i=0;str[i];i++)
198 	if ((unsigned char)str[i]>0x7F) return 0;
199     return 1;
200 }
201 
rccStringSizedGetChars(const char * str,size_t size)202 size_t rccStringSizedGetChars(const char *str, size_t size) {
203     size_t i, skip = 0, chars = 0;
204     const unsigned char *tmp;
205 
206     tmp = (unsigned char*)rccGetString(str);
207 
208     for (i=0;(size?(size-i):tmp[i]);i++) {
209 	if (skip) {
210 	    skip--;
211 	    continue;
212 	}
213 
214 	if (tmp[i]<0x80) skip = 0;
215 	else if ((tmp[i]>0xBF)&&(tmp[i]<0xE0)) skip = 1;
216 	else if ((tmp[i]>0xDF)&&(tmp[i]<0xF0)) skip = 2;
217 	else if ((tmp[i]>0xEF)&&(tmp[i]<0xF8)) skip = 3;
218 	else skip = 4;
219 	chars++;
220     }
221 
222     return chars;
223 }
224