Commit | Line | Data |
---|---|---|
970ed795 EL |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Copyright (c) 2000-2014 Ericsson Telecom AB | |
3 | // All rights reserved. This program and the accompanying materials | |
4 | // are made available under the terms of the Eclipse Public License v1.0 | |
5 | // which accompanies this distribution, and is available at | |
6 | // http://www.eclipse.org/legal/epl-v10.html | |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | #include <TTCN3.hh> | |
9 | #include <iconv.h> | |
10 | #include <errno.h> | |
11 | #include <vector> | |
12 | ||
13 | #if defined(WIN32) | |
14 | #include <cygwin/version.h> | |
15 | #endif | |
16 | ||
17 | #if defined(LINUX) || defined(INTERIX) || (CYGWIN_VERSION_DLL_MAJOR >= 1007) | |
18 | #define ICONV_INPUT_TYPE char* | |
19 | #else | |
20 | #define ICONV_INPUT_TYPE const char* | |
21 | #endif | |
22 | ||
23 | static const universal_char ucs4_bom = { 0,0,0xFE,0xFF }; | |
24 | ||
25 | namespace converter | |
26 | { | |
27 | // Convert from octetstring in UTF-8 to universal charstring | |
28 | INTEGER o2u(const CHARSTRING& encoding, const OCTETSTRING& input, UNIVERSAL_CHARSTRING& output) | |
29 | { | |
30 | errno = 0; | |
31 | iconv_t t = iconv_open("UCS-4BE", (const char*)encoding); // to, from | |
32 | if ((iconv_t)-1 == t) { | |
33 | perror(encoding); | |
34 | return errno; | |
35 | } | |
36 | size_t inbytesleft = input.lengthof(); | |
37 | ICONV_INPUT_TYPE inptr = (ICONV_INPUT_TYPE)(const unsigned char *)input; | |
38 | ||
39 | // Scott Meyers, Effective STL, Item 16. | |
40 | // Don't even think of using Titan's vector like this! | |
41 | std::vector<universal_char> outbuf(inbytesleft + 1); | |
42 | // +1 for the BOM that Solaris iconv likes to put in at the front | |
43 | char* outptr = (char*)&outbuf.front(); | |
44 | size_t const outbytes = outbuf.size() * 4; // size is in universal_char | |
45 | size_t outbytesleft = outbytes; // will be modified by iconv | |
46 | ||
47 | size_t rez = iconv(t, &inptr, &inbytesleft, &outptr, &outbytesleft); | |
48 | if (rez == (size_t)-1) { | |
49 | perror("*** iconv ***"); // oh dear | |
50 | } | |
51 | else { | |
52 | size_t is_bom = ( ucs4_bom == outbuf.front() ); | |
53 | output = UNIVERSAL_CHARSTRING((outbytes - outbytesleft - is_bom) / 4, &outbuf[is_bom]); | |
54 | errno = 0; // Solaris iconv may set errno to nonzero even after successful conversion :-O | |
55 | } | |
56 | iconv_close(t); | |
57 | ||
58 | return errno; | |
59 | } | |
60 | ||
61 | // Convert from universal charstring to octetstring in UTF-8 | |
62 | INTEGER u2o(const CHARSTRING& encoding, const UNIVERSAL_CHARSTRING& input, OCTETSTRING& output) | |
63 | { | |
64 | errno = 0; | |
65 | iconv_t t = iconv_open((const char*)encoding, "UCS-4BE"); // to, from | |
66 | if ((iconv_t)-1 == t) { | |
67 | perror(encoding); | |
68 | return errno; | |
69 | } | |
70 | ||
71 | size_t inbytesleft = input.lengthof(); // in characters | |
72 | size_t to_be = inbytesleft * 6; // max 6 bytes in UTF-8 per character | |
73 | inbytesleft *= 4; // count in bytes | |
74 | ||
75 | char* const inbuf = (char*)input.operator const universal_char*(); | |
76 | ICONV_INPUT_TYPE inptr = inbuf; // will be modified by iconv | |
77 | std::vector<unsigned char> outbuf(to_be | !to_be); | |
78 | // to_be, or not to_be, that is the question. | |
79 | // This makes sure that the vector's size is at least 1. | |
80 | char* outptr = (char*)&outbuf.front(); | |
81 | ||
82 | size_t rez = iconv(t, &inptr, &inbytesleft, &outptr, &to_be); | |
83 | if (rez == (size_t)-1) { | |
84 | perror("*** iconv ***"); // oh dear | |
85 | } | |
86 | else { | |
87 | output = OCTETSTRING(outbuf.size() - (to_be | !to_be), &outbuf.front()); | |
88 | errno = 0; // Solaris iconv may set errno to nonzero even after successful conversion :-O | |
89 | } | |
90 | iconv_close(t); | |
91 | ||
92 | return errno; | |
93 | } | |
94 | ||
95 | } // namespace | |
96 | ||
97 | // Drag o2u and u2o out to the global namespace for compatibility with old names. | |
98 | // Ifdef-ing the namespace away will probably fail when this file is used | |
99 | // from projects where old naming is permanently disabled. | |
100 | ||
101 | INTEGER o2u(const CHARSTRING& encoding, const OCTETSTRING& input, UNIVERSAL_CHARSTRING& output) { | |
102 | return converter::o2u(encoding, input, output); | |
103 | } | |
104 | ||
105 | INTEGER u2o(const CHARSTRING& encoding, const UNIVERSAL_CHARSTRING& input, OCTETSTRING& output) { | |
106 | return converter::u2o(encoding, input, output); | |
107 | } | |
108 |