Add check for integer overflow in odr_write YAZ-816
[yaz-moved-to-github.git] / src / icu_casemap.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file
8  * \brief ICU character case (u_strToUpper, etc)
9  */
10
11 #if HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #if YAZ_HAVE_ICU
16 #include <yaz/xmalloc.h>
17
18 #include <yaz/icu_I18N.h>
19
20 #include <yaz/log.h>
21
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25
26 #include <unicode/ustring.h>
27
28 struct icu_casemap
29 {
30     char action;
31 };
32
33 struct icu_casemap *icu_casemap_create(char action, UErrorCode *status)
34 {
35     struct icu_casemap *casemap
36         = (struct icu_casemap *) xmalloc(sizeof(struct icu_casemap));
37     casemap->action = action;
38
39     switch (casemap->action)
40     {
41     case 'l':
42     case 'L':
43     case 'u':
44     case 'U':
45     case 't':
46     case 'T':
47     case 'f':
48     case 'F':
49         break;
50     default:
51         icu_casemap_destroy(casemap);
52         return 0;
53     }
54     return casemap;
55 }
56
57 struct icu_casemap *icu_casemap_clone(struct icu_casemap *old)
58 {
59     struct icu_casemap * casemap
60         = (struct icu_casemap *) xmalloc(sizeof(struct icu_casemap));
61     casemap->action = old->action;
62     return casemap;
63 }
64
65 void icu_casemap_destroy(struct icu_casemap * casemap)
66 {
67     xfree(casemap);
68 }
69
70 int icu_casemap_casemap(struct icu_casemap *casemap,
71                         struct icu_buf_utf16 *dest16,
72                         struct icu_buf_utf16 *src16,
73                         UErrorCode *status,
74                         const char *locale)
75 {
76     if (!casemap)
77         return 0;
78
79     return icu_utf16_casemap(dest16, src16, locale,
80                              casemap->action, status);
81 }
82
83
84 static uint32_t icu_utf16_sub(struct icu_buf_utf16 *dest16,
85                           struct icu_buf_utf16 *src16,
86                           const char *locale, char action,
87                           UErrorCode *status)
88 {
89     switch (action)
90     {
91     case 'l':
92     case 'L':
93         return u_strToLower(dest16->utf16, dest16->utf16_cap,
94                             src16->utf16, src16->utf16_len,
95                             locale, status);
96     case 'u':
97     case 'U':
98         return u_strToUpper(dest16->utf16, dest16->utf16_cap,
99                             src16->utf16, src16->utf16_len,
100                             locale, status);
101         break;
102     case 't':
103     case 'T':
104         return u_strToTitle(dest16->utf16, dest16->utf16_cap,
105                             src16->utf16, src16->utf16_len,
106                             0, locale, status);
107         break;
108     case 'f':
109     case 'F':
110         return u_strFoldCase(dest16->utf16, dest16->utf16_cap,
111                              src16->utf16, src16->utf16_len,
112                              U_FOLD_CASE_DEFAULT, status);
113         break;
114     default:
115         *status = U_UNSUPPORTED_ERROR;
116         break;
117     }
118     return 0;
119 }
120
121
122 int icu_utf16_casemap(struct icu_buf_utf16 *dest16,
123                       struct icu_buf_utf16 *src16,
124                       const char *locale, char action,
125                       UErrorCode *status)
126 {
127     int32_t dest16_len = 0;
128
129     if (!src16->utf16_len)
130     {           /* guarding for empty source string */
131         if (dest16->utf16)
132             dest16->utf16[0] = (UChar) 0;
133         dest16->utf16_len = 0;
134         return U_ZERO_ERROR;
135     }
136
137     dest16_len = icu_utf16_sub(dest16, src16, locale, action, status);
138
139     /* check for buffer overflow, resize and retry */
140     if (*status == U_BUFFER_OVERFLOW_ERROR
141         && dest16 != src16)      /* do not resize if in-place conversion */
142     {
143         icu_buf_utf16_resize(dest16, dest16_len * 2);
144         *status = U_ZERO_ERROR;
145
146         icu_utf16_sub(dest16, src16, locale, action, status);
147     }
148
149     if (U_SUCCESS(*status) && dest16_len <= dest16->utf16_cap)
150         dest16->utf16_len = dest16_len;
151     else
152     {
153         if (dest16->utf16)
154             dest16->utf16[0] = (UChar) 0;
155         dest16->utf16_len = 0;
156     }
157
158     return *status;
159 }
160
161
162 #endif /* YAZ_HAVE_ICU */
163
164 /*
165  * Local variables:
166  * c-basic-offset: 4
167  * c-file-style: "Stroustrup"
168  * indent-tabs-mode: nil
169  * End:
170  * vim: shiftwidth=4 tabstop=8 expandtab
171  */
172