activerecord-ingres-adapter 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG +69 -0
- data/Gemfile +7 -0
- data/LICENSE +258 -0
- data/README.md +69 -0
- data/Rakefile +0 -0
- data/activerecord_ingres_adapter.gemspec +19 -0
- data/ext/Ingres.c +3889 -0
- data/ext/Ingres.h +318 -0
- data/ext/Unicode.c +219 -0
- data/ext/Unicode.h +56 -0
- data/ext/createMake.bat +1 -0
- data/ext/extconf.rb +85 -0
- data/ext/tests/config.rb +11 -0
- data/ext/tests/tc_connect.rb +12 -0
- data/ext/tests/tc_connect_hash.rb +31 -0
- data/ext/tests/tc_connect_with_login_only.rb +14 -0
- data/ext/tests/tc_connect_with_login_password.rb +12 -0
- data/ext/tests/tc_dual_connections.rb +14 -0
- data/ext/tests/tc_env_date_format.rb +47 -0
- data/ext/tests/tc_query_simple.rb +29 -0
- data/ext/tests/tc_query_username.rb +22 -0
- data/ext/tests/tc_transactions_savepoint.rb +109 -0
- data/ext/tests/tc_type_date_fetch.rb +22 -0
- data/ext/tests/tc_type_lob_fetch.rb +20 -0
- data/ext/tests/ts_all.rb +28 -0
- data/ext/tests/ts_connect.rb +5 -0
- data/ext/tests/ts_environment.rb +1 -0
- data/ext/tests/ts_execute.rb +1 -0
- data/ext/tests/ts_transactions.rb +3 -0
- data/ext/tests/ts_types.rb +2 -0
- data/lib/active_record/connection_adapters/ingres_adapter.rb +786 -0
- data/lib/activerecord-ingres-adapter.rb +2 -0
- data/lib/arel/visitors/ingres.rb +30 -0
- metadata +80 -0
data/ext/Ingres.h
ADDED
@@ -0,0 +1,318 @@
|
|
1
|
+
/*
|
2
|
+
** Copyright (c) 2009 Ingres Corporation
|
3
|
+
**
|
4
|
+
** This program is free software; you can redistribute it and/or modify
|
5
|
+
** it under the terms of the GNU General Public License version 2 as
|
6
|
+
** published by the Free Software Foundation.
|
7
|
+
**
|
8
|
+
** This program is distributed in the hope that it will be useful,
|
9
|
+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
** GNU General Public License for more details.
|
12
|
+
**
|
13
|
+
** You should have received a copy of the GNU General Public License along
|
14
|
+
** with this program; if not, write to the Free Software Foundation, Inc.,
|
15
|
+
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
16
|
+
*/
|
17
|
+
|
18
|
+
/* static char Sccsid[] = "$Id$"; */
|
19
|
+
|
20
|
+
/*
|
21
|
+
** INGRES.H
|
22
|
+
**
|
23
|
+
** History
|
24
|
+
** 08/24/2009 (grant.croker@ingres.com)
|
25
|
+
** Created
|
26
|
+
** 11/09/2009 (grant.croker@ingres.com)
|
27
|
+
** Add the ability to set the date format for Ingres date values
|
28
|
+
** from within Ruby
|
29
|
+
** 03/30/2010 (grant.croker@ingres.com)
|
30
|
+
** Fix #565 - Compilation errors with Redhat ES 5.4 (x86-64)
|
31
|
+
** 04/07/2010 (grant.croker@ingres.com)
|
32
|
+
** Add missing #include for version.h
|
33
|
+
*/
|
34
|
+
|
35
|
+
/* #include <version.h> */
|
36
|
+
|
37
|
+
/* Constants */
|
38
|
+
#define RUBY_INGRES_VERSION "1.4.1"
|
39
|
+
#define RUBY_INGRES_API IIAPI_VERSION
|
40
|
+
|
41
|
+
#define RUBY_STRING "STRING"
|
42
|
+
#define RUBY_INTEGER "INTEGER"
|
43
|
+
#define RUBY_BYTE "BYTE"
|
44
|
+
#define RUBY_TEXT "TEXT"
|
45
|
+
#define RUBY_VARCHAR "VARCHAR"
|
46
|
+
#define RUBY_DATE "DATE"
|
47
|
+
#define RUBY_DOUBLE "DOUBLE"
|
48
|
+
#define RUBY_TINYINT "TINYINT"
|
49
|
+
#define RUBY_LOB "LOB"
|
50
|
+
#define RUBY_UNMAPPED "UNMAPPED_DATATYPE"
|
51
|
+
#define ERROR_MESSAGE_HEADER "Ingres Diagnostic Messages:\n"
|
52
|
+
#define RubyParamOffset(ip, ipc) ((ip - ipc) * (2 + ipc))
|
53
|
+
|
54
|
+
#define RUBY_NVARCHAR_PARAMETER 'N'
|
55
|
+
#define RUBY_NCHAR_PARAMETER 'n'
|
56
|
+
#define RUBY_VARCHAR_PARAMETER 'v'
|
57
|
+
#define RUBY_DECIMAL_PARAMETER 'D'
|
58
|
+
#define RUBY_LONG_BYTE_PARAMETER 'B'
|
59
|
+
#define RUBY_LONG_TEXT_PARAMETER 'T'
|
60
|
+
#define RUBY_LONG_VARCHAR_PARAMETER 'V'
|
61
|
+
|
62
|
+
#define RUBY_INTEGER_PARAMETER 'i'
|
63
|
+
#define RUBY_BYTE_PARAMETER 'b'
|
64
|
+
#define RUBY_CHAR_PARAMETER 'c'
|
65
|
+
#define RUBY_DATE_PARAMETER 'd'
|
66
|
+
#define RUBY_TEXT_PARAMETER 't'
|
67
|
+
#define RUBY_FLOAT_PARAMETER 'f'
|
68
|
+
|
69
|
+
#define DECIMAL_BUFFER_LEN 16
|
70
|
+
#define DECIMAL_PRECISION 31
|
71
|
+
#define DECIMAL_SCALE 15
|
72
|
+
#define DOUBLE_PRECISION 31
|
73
|
+
#define DOUBLE_SCALE 15
|
74
|
+
#define MAX_CHAR_SIZE 32000 /* max #bytes Ingres (var)char */
|
75
|
+
#define LOB_SEGMENT_SIZE 8192
|
76
|
+
|
77
|
+
/* Ingres 2.6 is missing a define for IIAPI_CPV_DFRMT_ISO4 */
|
78
|
+
#if !defined(IIAPI_CPV_DFRMT_ISO4)
|
79
|
+
#define IIAPI_CPV_DFRMT_ISO4 9
|
80
|
+
#endif
|
81
|
+
|
82
|
+
/* Query types */
|
83
|
+
|
84
|
+
#define INGRES_SQL_SELECT 0
|
85
|
+
#define INGRES_SQL_INSERT 1
|
86
|
+
#define INGRES_SQL_UPDATE 2
|
87
|
+
#define INGRES_SQL_DELETE 3
|
88
|
+
#define INGRES_SQL_COMMIT 4
|
89
|
+
#define INGRES_SQL_ROLLBACK 5
|
90
|
+
#define INGRES_SQL_OPEN 6
|
91
|
+
#define INGRES_SQL_CLOSE 7
|
92
|
+
#define INGRES_SQL_CONNECT 8
|
93
|
+
#define INGRES_SQL_DISCONNECT 9
|
94
|
+
#define INGRES_SQL_GETDBEVENT 10
|
95
|
+
#define INGRES_SQL_SAVEPOINT 11
|
96
|
+
#define INGRES_SQL_AUTOCOMMIT 12
|
97
|
+
#define INGRES_SQL_EXECUTE_PROCEDURE 13
|
98
|
+
#define INGRES_SQL_CALL 14
|
99
|
+
#define INGRES_SQL_COPY 15
|
100
|
+
#define INGRES_SQL_CREATE 16
|
101
|
+
#define INGRES_SQL_ALTER 17
|
102
|
+
#define INGRES_SQL_DROP 18
|
103
|
+
#define INGRES_SQL_GRANT 19
|
104
|
+
#define INGRES_SQL_REVOKE 20
|
105
|
+
#define INGRES_SQL_MODIFY 21
|
106
|
+
#define INGRES_SQL_SET 22
|
107
|
+
/* Not really an SQL Statement but INGRES_START_TRANSACTION is expected to be handled as one */
|
108
|
+
#define INGRES_START_TRANSACTION 23
|
109
|
+
#define INGRES_SQL_ROLLBACK_WORK_TO 24
|
110
|
+
#define INGRES_SQL_ROLLBACK_TO 25
|
111
|
+
|
112
|
+
#define INGRES_NO_OF_COMMANDS 26
|
113
|
+
static struct
|
114
|
+
{
|
115
|
+
char *command;
|
116
|
+
int code;
|
117
|
+
int length ;
|
118
|
+
} SQL_COMMANDS [INGRES_NO_OF_COMMANDS] =
|
119
|
+
{
|
120
|
+
{ "SELECT", INGRES_SQL_SELECT, 6 },
|
121
|
+
{ "INSERT", INGRES_SQL_INSERT, 6 },
|
122
|
+
{ "UPDATE", INGRES_SQL_UPDATE, 6 },
|
123
|
+
{ "DELETE", INGRES_SQL_DELETE, 6 },
|
124
|
+
{ "COMMIT", INGRES_SQL_COMMIT, 6 },
|
125
|
+
{ "ROLLBACK", INGRES_SQL_ROLLBACK, 8 },
|
126
|
+
{ "OPEN", INGRES_SQL_OPEN, 4 },
|
127
|
+
{ "CLOSE", INGRES_SQL_CLOSE, 5 },
|
128
|
+
{ "CONNECT", INGRES_SQL_CONNECT, 7 },
|
129
|
+
{ "DISCONNECT", INGRES_SQL_DISCONNECT, 10 },
|
130
|
+
{ "GET DBEVENT", INGRES_SQL_GETDBEVENT, 11 },
|
131
|
+
{ "SAVEPOINT", INGRES_SQL_SAVEPOINT, 9 },
|
132
|
+
{ "SET AUTOCOMMIT", INGRES_SQL_AUTOCOMMIT, 14 },
|
133
|
+
{ "EXECUTE PROCEDURE", INGRES_SQL_EXECUTE_PROCEDURE, 17 },
|
134
|
+
{ "CALL", INGRES_SQL_CALL, 4 },
|
135
|
+
{ "COPY", INGRES_SQL_COPY, 4 },
|
136
|
+
{ "CREATE", INGRES_SQL_CREATE, 6 },
|
137
|
+
{ "ALTER", INGRES_SQL_ALTER, 5 },
|
138
|
+
{ "DROP", INGRES_SQL_DROP, 4 },
|
139
|
+
{ "GRANT", INGRES_SQL_GRANT, 5 },
|
140
|
+
{ "REVOKE", INGRES_SQL_REVOKE, 6 },
|
141
|
+
{ "MODIFY", INGRES_SQL_MODIFY, 6 },
|
142
|
+
{ "SET", INGRES_SQL_SET, 3 },
|
143
|
+
{ "START TRANSACTION", INGRES_START_TRANSACTION, 17 },
|
144
|
+
{ "ROLLBACK WORK TO", INGRES_SQL_ROLLBACK_WORK_TO, 16 },
|
145
|
+
{ "ROLLBACK TO", INGRES_SQL_ROLLBACK_TO, 11 },
|
146
|
+
};
|
147
|
+
|
148
|
+
#define INGRES_NO_CONN_PARAMS 1
|
149
|
+
static struct
|
150
|
+
{
|
151
|
+
char *paramName;
|
152
|
+
II_LONG paramID;
|
153
|
+
} CONN_PARAMS [INGRES_NO_CONN_PARAMS] =
|
154
|
+
{
|
155
|
+
{"date_format", IIAPI_CP_DATE_FORMAT }, /* for SELECT VARCHAR(date_col) */
|
156
|
+
};
|
157
|
+
|
158
|
+
#define INGRES_NO_ENV_PARAMS 1
|
159
|
+
static struct
|
160
|
+
{
|
161
|
+
char *paramName;
|
162
|
+
II_LONG paramID;
|
163
|
+
} ENV_PARAMS [INGRES_NO_ENV_PARAMS] =
|
164
|
+
{
|
165
|
+
{"date_format", IIAPI_EP_DATE_FORMAT }, /* for SELECT date_col */
|
166
|
+
};
|
167
|
+
|
168
|
+
/* Cursor Modes */
|
169
|
+
#define INGRES_CURSOR_READONLY 0
|
170
|
+
#define INGRES_CURSOR_UPDATE 1
|
171
|
+
|
172
|
+
typedef struct _II_GLOBALS
|
173
|
+
{
|
174
|
+
II_PTR envHandle;
|
175
|
+
int debug;
|
176
|
+
int debug_connection;
|
177
|
+
int debug_sql;
|
178
|
+
int debug_termination;
|
179
|
+
int debug_transactions;
|
180
|
+
} II_GLOBALS;
|
181
|
+
|
182
|
+
typedef struct _II_SAVEPOINT_ENTRY
|
183
|
+
{
|
184
|
+
char *savePtName;
|
185
|
+
II_PTR savePtHandle;
|
186
|
+
II_PTR nextSavePtEntry;
|
187
|
+
} II_SAVEPOINT_ENTRY;
|
188
|
+
|
189
|
+
typedef struct _II_CONN
|
190
|
+
{
|
191
|
+
int autocommit;
|
192
|
+
II_PTR connHandle;
|
193
|
+
II_PTR tranHandle;
|
194
|
+
II_PTR stmtHandle;
|
195
|
+
II_PTR envHandle;
|
196
|
+
II_LONG fieldCount;
|
197
|
+
II_LONG lobSegmentSize;
|
198
|
+
IIAPI_DESCRIPTOR *descriptor;
|
199
|
+
II_CHAR *errorText;
|
200
|
+
II_CHAR sqlstate[6];
|
201
|
+
II_LONG errorCode;
|
202
|
+
int apiLevel;
|
203
|
+
int paramCount;
|
204
|
+
int allow_persistent;
|
205
|
+
int num_persistent;
|
206
|
+
char *cursor_id;
|
207
|
+
long cursor_mode;
|
208
|
+
char *currentDatabase;
|
209
|
+
int queryType;
|
210
|
+
VALUE keep_me;
|
211
|
+
VALUE resultset;
|
212
|
+
VALUE r_column_names;
|
213
|
+
VALUE r_data_sizes;
|
214
|
+
VALUE r_data_types;
|
215
|
+
II_LONG columnCount;
|
216
|
+
II_PTR savePtList;
|
217
|
+
II_SAVEPOINT_ENTRY *lastSavePtEntry;/* Pointer to the last savePtEntry on savePtList */
|
218
|
+
} II_CONN;
|
219
|
+
|
220
|
+
typedef struct _RUBY_IIAPI_DATAVALUE
|
221
|
+
{
|
222
|
+
IIAPI_DATAVALUE dataValue[1];
|
223
|
+
long dv_length;
|
224
|
+
} RUBY_IIAPI_DATAVALUE;
|
225
|
+
|
226
|
+
typedef struct _RUBY_PARAMETER
|
227
|
+
{
|
228
|
+
VALUE vkey;
|
229
|
+
VALUE vtype;
|
230
|
+
VALUE vvalue;
|
231
|
+
} RUBY_PARAMETER;
|
232
|
+
|
233
|
+
#define rb_define_singleton_alias(klass,new,old) rb_define_alias(rb_singleton_class(klass),new,old)
|
234
|
+
|
235
|
+
|
236
|
+
/*
|
237
|
+
* Function declarations
|
238
|
+
*/
|
239
|
+
VALUE ii_execute (int param_argc, VALUE * param_argv, VALUE param_self);
|
240
|
+
VALUE ii_connect (int param_argc, VALUE * param_argv, VALUE param_self);
|
241
|
+
static VALUE ing_disconnect (VALUE param_self);
|
242
|
+
VALUE ing_connect (VALUE param_self, VALUE param_targetDB);
|
243
|
+
static void ii_conn_init(II_CONN *ii_conn);
|
244
|
+
VALUE ing_init (int argc, VALUE *argv, VALUE self);
|
245
|
+
void ing_api_init ();
|
246
|
+
static VALUE rb_ingres_alloc(VALUE klass);
|
247
|
+
static void free_ii_conn (II_CONN *ing_conn);
|
248
|
+
static void ing_starttransaction();
|
249
|
+
static void ing_commit();
|
250
|
+
static void ing_rollback();
|
251
|
+
VALUE ing_query (char *param_sqlText);
|
252
|
+
static int ing_querytype(char *queryText);
|
253
|
+
VALUE ing_execute (VALUE argc, VALUE *argv, VALUE self);
|
254
|
+
II_PTR executeQuery (II_CONN *ii_conn, char *param_sqlText);
|
255
|
+
static void ing_conn_init(II_CONN *ing_conn);
|
256
|
+
void ii_api_query_close (II_CONN *ii_conn);
|
257
|
+
void ii_api_connect (II_CONN *ii_conn, char *param_targetDB, char *param_username, char *param_password);
|
258
|
+
void ii_api_commit (II_CONN *ii_conn);
|
259
|
+
static int ii_query_type(char *queryText);
|
260
|
+
void ii_api_rollback (II_CONN *ii_conn, II_SAVEPOINT_ENTRY *savePtEntry);
|
261
|
+
void ii_api_disconnect( II_CONN *ii_conn);
|
262
|
+
void ii_api_savepoint (II_CONN *ii_conn, VALUE savePtName);
|
263
|
+
void ii_free_savePtEntries (II_SAVEPOINT_ENTRY *savePtEntry);
|
264
|
+
|
265
|
+
void ii_api_set_connect_param (II_CONN *ii_conn, II_LONG paramID, VALUE paramValue);
|
266
|
+
void ii_api_set_env_param (II_LONG paramID, VALUE paramValue);
|
267
|
+
|
268
|
+
/* Transaction control */
|
269
|
+
VALUE ii_commit (VALUE param_self);
|
270
|
+
VALUE ii_rollback (int param_argc, VALUE * param_argv, VALUE param_self);
|
271
|
+
VALUE ii_savepoint (VALUE param_self, VALUE param_savepointName);
|
272
|
+
VALUE ii_savepoint_name(II_CONN *ii_conn, char *statement);
|
273
|
+
|
274
|
+
/* Memory Allocation/Deallocation */
|
275
|
+
void *ii_allocate (size_t nitems, size_t size);
|
276
|
+
void *ii_reallocate (void *oldPtr, size_t nitems, size_t size);
|
277
|
+
void ii_free (void **ptr);
|
278
|
+
|
279
|
+
/* TODO - The following has been taken from the Ingres CL and should be removed/replaced at some point */
|
280
|
+
# define NULLCHAR ('\0') /* string terminator */
|
281
|
+
# define EOS NULLCHAR
|
282
|
+
# define CM_A_DBL1 0x80 /* 1st byte of double byte character */
|
283
|
+
# define CM_A_SPACE 0x10 /* SPACE */
|
284
|
+
# define cmdblspace(str) (((*(str)&0377) == 0xA1) && ((*((str)+1)&0377) == 0xA1))
|
285
|
+
|
286
|
+
# if defined(NT_GENERIC)
|
287
|
+
FUNC_EXTERN u_i2 *CMgetAttrTab ();
|
288
|
+
FUNC_EXTERN char *CMgetCaseTab ();
|
289
|
+
# endif
|
290
|
+
|
291
|
+
# define CMbytecnt(ptr) (1)
|
292
|
+
# define CMnext(str) (++(str))
|
293
|
+
# define CMdbl1st(str) (FALSE)
|
294
|
+
|
295
|
+
# if defined(_MSC_VER) || (defined(NT_GENERIC) && defined(IMPORT_DLL_DATA))
|
296
|
+
# define CMwhite(str) ((((u_i2 *)CMgetAttrTab())[*(str)&0377] & CM_A_SPACE) != 0)
|
297
|
+
# else /* NT_GENERIC && IMPORT_DLL_DATA */
|
298
|
+
# define CMwhite(str) ((CM_AttrTab[*(str)&0377] & CM_A_SPACE) != 0)
|
299
|
+
# endif /* NT_GENERIC && IMPORT_DLL_DATA */
|
300
|
+
|
301
|
+
/* available via Ingres Compatibility Layer */
|
302
|
+
/* TODO - Remove dependency on the Ingres CL */
|
303
|
+
size_t STtrmwhite (register char *string);
|
304
|
+
|
305
|
+
/* Certain Ruby releases shipped with different Linux distributions do not contain
|
306
|
+
* the necessary defines. E.g. RedHat ES 5.4 ships with Ruby 1.8.5.
|
307
|
+
*/
|
308
|
+
#ifdef RUBY_VERSION_CODE
|
309
|
+
# if RUBY_VERSION_CODE < 186
|
310
|
+
# define RARRAY_LEN(s) (RARRAY(s)->len)
|
311
|
+
# define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
312
|
+
# define RSTRING_LEN(s) (RSTRING(s)->len)
|
313
|
+
# endif /* RUBY_VERSION_CODE < 186 */
|
314
|
+
#endif
|
315
|
+
|
316
|
+
/*
|
317
|
+
vim: ts=2 sw=2 expandtab
|
318
|
+
*/
|
data/ext/Unicode.c
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
/*
|
2
|
+
** Copyright (c) 2009 Ingres Corporation
|
3
|
+
**
|
4
|
+
** This program is free software; you can redistribute it and/or modify
|
5
|
+
** it under the terms of the GNU General Public License version 2 as
|
6
|
+
** published by the Free Software Foundation.
|
7
|
+
**
|
8
|
+
** This program is distributed in the hope that it will be useful,
|
9
|
+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
** GNU General Public License for more details.
|
12
|
+
**
|
13
|
+
** You should have received a copy of the GNU General Public License along
|
14
|
+
** with this program; if not, write to the Free Software Foundation, Inc.,
|
15
|
+
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
16
|
+
*/
|
17
|
+
|
18
|
+
/* static char Sccsid[] = "$Id$"; */
|
19
|
+
|
20
|
+
/*
|
21
|
+
** UNCIODE.C
|
22
|
+
**
|
23
|
+
** History
|
24
|
+
** 24-Aug-2009 (Grant.Croker@ingres.com)
|
25
|
+
** Created / Imported from Ingres.c
|
26
|
+
*/
|
27
|
+
|
28
|
+
#include "Unicode.h"
|
29
|
+
|
30
|
+
int utf8_to_utf16 (UTF8 * sourceStart, const UTF8 * sourceEnd, UCS2 * targetStart, const UCS2 * targetEnd, long *reslen)
|
31
|
+
{
|
32
|
+
int result = FALSE;
|
33
|
+
register UTF8 *source = sourceStart;
|
34
|
+
register UCS2 *target = targetStart;
|
35
|
+
register UCS4 ch;
|
36
|
+
register u_i2 extraBytesToWrite;
|
37
|
+
const i4 halfShift = 10;
|
38
|
+
|
39
|
+
const UCS4 halfBase = 0x0010000UL, halfMask = 0x3FFUL,
|
40
|
+
kReplacementCharacter = 0x0000FFFDUL,
|
41
|
+
kMaximumUCS2 = 0x0000FFFFUL, kMaximumUCS4 = 0x7FFFFFFFUL,
|
42
|
+
kSurrogateHighStart = 0xD800UL, kSurrogateHighEnd = 0xDBFFUL,
|
43
|
+
kSurrogateLowStart = 0xDC00UL, kSurrogateLowEnd = 0xDFFFUL;
|
44
|
+
|
45
|
+
UCS4 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL
|
46
|
+
};
|
47
|
+
|
48
|
+
char bytesFromUTF8[256] = {
|
49
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
50
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
51
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
52
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
53
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
54
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
55
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
56
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
|
57
|
+
};
|
58
|
+
|
59
|
+
while (source < sourceEnd)
|
60
|
+
{
|
61
|
+
ch = 0;
|
62
|
+
extraBytesToWrite = bytesFromUTF8[*source];
|
63
|
+
if (source + extraBytesToWrite > sourceEnd)
|
64
|
+
{
|
65
|
+
*reslen = target - targetStart;
|
66
|
+
return TRUE;
|
67
|
+
}
|
68
|
+
|
69
|
+
switch (extraBytesToWrite) /* note: code falls through cases! */
|
70
|
+
{
|
71
|
+
case 5:
|
72
|
+
ch += *source++;
|
73
|
+
ch <<= 6;
|
74
|
+
case 4:
|
75
|
+
ch += *source++;
|
76
|
+
ch <<= 6;
|
77
|
+
case 3:
|
78
|
+
ch += *source++;
|
79
|
+
ch <<= 6;
|
80
|
+
case 2:
|
81
|
+
ch += *source++;
|
82
|
+
ch <<= 6;
|
83
|
+
case 1:
|
84
|
+
ch += *source++;
|
85
|
+
ch <<= 6;
|
86
|
+
case 0:
|
87
|
+
ch += *source++;
|
88
|
+
}
|
89
|
+
ch -= offsetsFromUTF8[extraBytesToWrite];
|
90
|
+
|
91
|
+
if (target >= targetEnd)
|
92
|
+
{
|
93
|
+
*reslen = target - targetStart;
|
94
|
+
return result;
|
95
|
+
}
|
96
|
+
|
97
|
+
if (ch <= kMaximumUCS2)
|
98
|
+
{
|
99
|
+
*target++ = ch;
|
100
|
+
}
|
101
|
+
else if (ch > kMaximumUCS4)
|
102
|
+
{
|
103
|
+
*target++ = kReplacementCharacter;
|
104
|
+
}
|
105
|
+
else
|
106
|
+
{
|
107
|
+
if (target + 1 >= targetEnd)
|
108
|
+
{
|
109
|
+
*reslen = target - targetStart;
|
110
|
+
return result;
|
111
|
+
}
|
112
|
+
ch -= halfBase;
|
113
|
+
*target++ = (ch >> halfShift) + kSurrogateHighStart;
|
114
|
+
*target++ = (ch & halfMask) + kSurrogateLowStart;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
*reslen = target - targetStart;
|
118
|
+
return result;
|
119
|
+
}
|
120
|
+
|
121
|
+
int utf16_to_utf8 (UCS2 * sourceStart, const UCS2 * sourceEnd, UTF8 * targetStart, const UTF8 * targetEnd, long *reslen)
|
122
|
+
{
|
123
|
+
int result = FALSE;
|
124
|
+
register UCS2 *source = sourceStart;
|
125
|
+
register UTF8 *target = targetStart;
|
126
|
+
register UCS4 ch, ch2;
|
127
|
+
register u_i2 bytesToWrite;
|
128
|
+
register const UCS4 byteMask = 0xBF;
|
129
|
+
register const UCS4 byteMark = 0x80;
|
130
|
+
const i4 halfShift = 10;
|
131
|
+
UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
132
|
+
|
133
|
+
const UCS4 halfBase = 0x0010000UL, halfMask = 0x3FFUL,
|
134
|
+
kReplacementCharacter = 0x0000FFFDUL,
|
135
|
+
kMaximumUCS2 = 0x0000FFFFUL, kMaximumUCS4 = 0x7FFFFFFFUL,
|
136
|
+
kSurrogateHighStart = 0xD800UL, kSurrogateHighEnd = 0xDBFFUL,
|
137
|
+
kSurrogateLowStart = 0xDC00UL, kSurrogateLowEnd = 0xDFFFUL;
|
138
|
+
|
139
|
+
|
140
|
+
while (source < sourceEnd)
|
141
|
+
{
|
142
|
+
bytesToWrite = 0;
|
143
|
+
ch = *source++;
|
144
|
+
if (ch >= kSurrogateHighStart && ch <= kSurrogateHighEnd && source < sourceEnd)
|
145
|
+
{
|
146
|
+
ch2 = *source;
|
147
|
+
if (ch2 >= kSurrogateLowStart && ch2 <= kSurrogateLowEnd)
|
148
|
+
{
|
149
|
+
ch = ((ch - kSurrogateHighStart) << halfShift) + (ch2 - kSurrogateLowStart) + halfBase;
|
150
|
+
++source;
|
151
|
+
}
|
152
|
+
}
|
153
|
+
if (ch < 0x80)
|
154
|
+
{
|
155
|
+
bytesToWrite = 1;
|
156
|
+
}
|
157
|
+
else if (ch < 0x800)
|
158
|
+
{
|
159
|
+
bytesToWrite = 2;
|
160
|
+
}
|
161
|
+
else if (ch < 0x10000)
|
162
|
+
{
|
163
|
+
bytesToWrite = 3;
|
164
|
+
}
|
165
|
+
else if (ch < 0x200000)
|
166
|
+
{
|
167
|
+
bytesToWrite = 4;
|
168
|
+
}
|
169
|
+
else if (ch < 0x4000000)
|
170
|
+
{
|
171
|
+
bytesToWrite = 5;
|
172
|
+
}
|
173
|
+
else if (ch <= kMaximumUCS4)
|
174
|
+
{
|
175
|
+
bytesToWrite = 6;
|
176
|
+
}
|
177
|
+
else
|
178
|
+
{
|
179
|
+
bytesToWrite = 2;
|
180
|
+
ch = kReplacementCharacter;
|
181
|
+
}
|
182
|
+
|
183
|
+
target += bytesToWrite;
|
184
|
+
if (target > targetEnd)
|
185
|
+
{
|
186
|
+
target -= bytesToWrite;
|
187
|
+
*reslen = target - targetStart;
|
188
|
+
return result;
|
189
|
+
}
|
190
|
+
switch (bytesToWrite) /* note: code falls through cases! */
|
191
|
+
{
|
192
|
+
case 6:
|
193
|
+
*--target = (ch | byteMark) & byteMask;
|
194
|
+
ch >>= 6;
|
195
|
+
case 5:
|
196
|
+
*--target = (ch | byteMark) & byteMask;
|
197
|
+
ch >>= 6;
|
198
|
+
case 4:
|
199
|
+
*--target = (ch | byteMark) & byteMask;
|
200
|
+
ch >>= 6;
|
201
|
+
case 3:
|
202
|
+
*--target = (ch | byteMark) & byteMask;
|
203
|
+
ch >>= 6;
|
204
|
+
case 2:
|
205
|
+
*--target = (ch | byteMark) & byteMask;
|
206
|
+
ch >>= 6;
|
207
|
+
case 1:
|
208
|
+
*--target = ch | firstByteMark[bytesToWrite];
|
209
|
+
}
|
210
|
+
target += bytesToWrite;
|
211
|
+
}
|
212
|
+
*reslen = target - targetStart;
|
213
|
+
return result;
|
214
|
+
}
|
215
|
+
|
216
|
+
|
217
|
+
/*
|
218
|
+
vim: ts=2 sw=2 expandtab
|
219
|
+
*/
|