/[svn]/qsampler/trunk/src/qsamplerUtilities.cpp
ViewVC logotype

Annotation of /qsampler/trunk/src/qsamplerUtilities.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3914 - (hide annotations) (download)
Fri Jun 4 22:22:41 2021 UTC (2 years, 11 months ago) by capela
File size: 7001 byte(s)
- lscpEscapePath(): add/fix utf8 support.
1 schoenebeck 1386 // qsamplerUtilities.cpp
2     //
3     /****************************************************************************
4 capela 3794 Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved.
5 schoenebeck 1667 Copyright (C) 2007, 2008 Christian Schoenebeck
6 schoenebeck 1386
7     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; either version 2
10     of the License, or (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License along
18     with this program; if not, write to the Free Software Foundation, Inc.,
19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20    
21     *****************************************************************************/
22    
23     #include "qsamplerUtilities.h"
24    
25 capela 1513 #include "qsamplerOptions.h"
26 schoenebeck 1386 #include "qsamplerMainForm.h"
27    
28 capela 3794 #include <QRegularExpression>
29 schoenebeck 1386
30 capela 1499
31 schoenebeck 1461 using namespace QSampler;
32    
33 schoenebeck 1402 namespace qsamplerUtilities {
34    
35 capela 3357 static int _hexToNumber ( char hex_digit )
36     {
37     switch (hex_digit) {
38     case '0': return 0;
39     case '1': return 1;
40     case '2': return 2;
41     case '3': return 3;
42     case '4': return 4;
43     case '5': return 5;
44     case '6': return 6;
45     case '7': return 7;
46     case '8': return 8;
47     case '9': return 9;
48 schoenebeck 1402
49 capela 3357 case 'a': return 10;
50     case 'b': return 11;
51     case 'c': return 12;
52     case 'd': return 13;
53     case 'e': return 14;
54     case 'f': return 15;
55 schoenebeck 1402
56 capela 3357 case 'A': return 10;
57     case 'B': return 11;
58     case 'C': return 12;
59     case 'D': return 13;
60     case 'E': return 14;
61     case 'F': return 15;
62 schoenebeck 1402
63 capela 3357 default: return 0;
64     }
65 schoenebeck 1402 }
66    
67 capela 3357 static int _hexsToNumber ( char hex0, char hex1 )
68     {
69     return _hexToNumber(hex1) * 16 + _hexToNumber(hex0);
70 schoenebeck 1402 }
71    
72 capela 3914 static bool _isHex ( char hex_digit )
73     {
74     return _hexToNumber ( hex_digit ) || hex_digit == '0';
75     }
76 capela 3357
77 schoenebeck 1402 // returns true if the connected LSCP server supports escape sequences
78 capela 3357 static bool _remoteSupportsEscapeSequences (void)
79     {
80     const lscpVersion_t version = getRemoteLscpVersion();
81     // LSCP v1.2 or younger required
82     return (version.major > 1 || (version.major == 1 && version.minor >= 2));
83 schoenebeck 1402 }
84    
85 capela 3357
86 schoenebeck 1386 // converts the given file path into a path as expected by LSCP 1.2
87 capela 3914 QByteArray lscpEscapePath ( const QString& sPath )
88 capela 1394 {
89 capela 3914 QByteArray path = sPath.toUtf8();
90     if (!_remoteSupportsEscapeSequences()) return path;
91 capela 1394
92 capela 3914 const char pathSeparator = '/';
93     int path_len = path.length();
94     char buf[5];
95 schoenebeck 1386
96 capela 3914 // Trying single pass to avoid redundant checks on extra run
97     for ( int i = 0; i < path_len; i++ ) {
98     // translate POSIX escape sequences
99     if (path[i] == '%') {
100     // replace POSIX path escape sequences (%HH) by LSCP escape sequences (\xHH)
101     // TODO: missing code for other systems like Windows
102     if (_isHex(path[i+1]) && _isHex(path[i+2])) {
103     path.replace (i, 1, "\\x");
104     path_len++;
105 capela 3357 i += 3;
106     continue;
107     }
108 capela 3914 // replace POSIX path escape sequence (%%) by its raw character
109     if (path[i+1] == '%') {
110     path.remove (i, 1);
111     path_len--;
112     continue;
113 capela 3357 }
114 capela 3914 continue;
115 capela 3357 }
116 capela 3914 // replace all non-basic characters by LSCP escape sequences
117     //
118     // match all non-alphanumerics
119     // (we could exclude much more characters here, but that way
120     // we're sure it just works^TM)
121     const char c = path[i];
122     if (
123     !(c >= '0' && c <= '9') &&
124     !(c >= 'a' && c <= 'z') &&
125     !(c >= 'A' && c <= 'Z') &&
126     #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
127     !(c == ':') &&
128     #endif
129     !(c == pathSeparator)
130     ) {
131     // convertion
132     ::snprintf(buf, sizeof(buf), "\\x%02x", static_cast<unsigned char>(c));
133     path = path.replace(i, 1, buf);
134     path_len += 3;
135     i += 3;
136     }
137 capela 3357 }
138 capela 1394
139 capela 3357 return path;
140 schoenebeck 1386 }
141    
142 capela 3357
143 schoenebeck 1402 // converts a path returned by a LSCP command (and may contain escape
144     // sequences) into the appropriate POSIX path
145 capela 3914 QString lscpEscapedPathToPosix ( const char* sPath )
146 capela 3357 {
147 capela 3914 if (!_remoteSupportsEscapeSequences()) return QString(sPath);
148 capela 1394
149 capela 3914 QByteArray path(sPath);
150     int path_len = path.length();
151 schoenebeck 1402
152 capela 3914 char cAscii[2] = "\0";
153     for ( int i = 0; i < path_len; i++) {
154     // first escape all percent ('%') characters for POSIX
155     if (path[i] == '%') {
156     path.insert(i, '%');
157     path_len++;
158     i++;
159 capela 3357 continue;
160     }
161 capela 3914 // resolve LSCP hex escape sequences (\xHH)
162     if (path[i] == '\\' && path[i+1] == 'x' && _isHex(path[i+2]) && _isHex(path[i+3])) {
163     const QByteArray sHex = path.mid(i + 2, 2).toLower();
164     // the slash has to be escaped for POSIX as well
165     if (sHex == "2f") {
166     path.replace(i, 4, "%2f");
167     // all other characters we simply decode
168     } else {
169     cAscii[0] = _hexsToNumber(sHex[1], sHex[0]);
170     path.replace(i, 4, cAscii);
171     }
172     path_len -= 3;
173     continue;
174     }
175 capela 3357 }
176    
177 capela 3914 return QString(path);
178 schoenebeck 1402 }
179    
180 capela 3357
181 schoenebeck 1667 // converts the given text as expected by LSCP 1.2
182     // (that is by encoding special characters with LSCP escape sequences)
183 capela 3914 QByteArray lscpEscapeText ( const QString& sText )
184 capela 3357 {
185 capela 3914 QByteArray text = sText.toUtf8();
186     if (!_remoteSupportsEscapeSequences()) return text;
187 schoenebeck 1667
188 capela 3914 int text_len = text.length();
189     char buf[5];
190 schoenebeck 1667
191 capela 3357 // replace all non-basic characters by LSCP escape sequences
192 capela 3914 for (int i = 0; i < text_len; ++i) {
193 capela 3357 // match all non-alphanumerics
194     // (we could exclude much more characters here, but that way
195     // we're sure it just works^TM)
196 capela 3914 const char c = text[i];
197 capela 3357 if (
198     !(c >= '0' && c <= '9') &&
199     !(c >= 'a' && c <= 'z') &&
200     !(c >= 'A' && c <= 'Z')
201     ) {
202     // convert the non-basic character into a LSCP escape sequence
203     ::snprintf(buf, sizeof(buf), "\\x%02x", static_cast<unsigned char>(c));
204     text.replace(i, 1, buf);
205 capela 3914 text_len += 3;
206 capela 3357 i += 3;
207     }
208     }
209 schoenebeck 1667
210 capela 3357 return text;
211 schoenebeck 1667 }
212    
213 capela 3357
214 schoenebeck 1402 // converts a text returned by a LSCP command and may contain escape
215     // sequences) into raw text, that is with all escape sequences decoded
216 capela 3914 QString lscpEscapedTextToRaw ( const char* sText )
217 capela 3357 {
218 capela 3914 if (!_remoteSupportsEscapeSequences()) return QString(sText);
219 schoenebeck 1402
220 capela 3914 QByteArray text(sText);
221     int text_len = text.length();
222     char sHex[2], cAscii[2] = "\0";
223 schoenebeck 1402
224 capela 3357 // resolve LSCP hex escape sequences (\xHH)
225 capela 3914 for (int i = 0; i < text_len; i++) {
226     if (text[i] != '\\' || text[i+1] != 'x') continue;
227    
228     sHex[0] = text[i+2], sHex[1] = text[i+3];
229     if (_isHex(sHex[0]) && _isHex(sHex[1])) {
230     cAscii[0] = _hexsToNumber(sHex[1], sHex[0]);
231     text.replace(i, 4, cAscii);
232     text_len -= 3;
233     }
234 capela 3357 }
235    
236 capela 3914 return QString(text);
237 schoenebeck 1402 }
238    
239 capela 1394 lscpVersion_t getRemoteLscpVersion (void)
240     {
241 schoenebeck 1386 lscpVersion_t result = { 0, 0 };
242    
243 schoenebeck 1461 MainForm* pMainForm = MainForm::getInstance();
244 capela 3555 if (pMainForm == nullptr)
245 schoenebeck 1402 return result;
246 capela 3555 if (pMainForm->client() == nullptr)
247 schoenebeck 1402 return result;
248 schoenebeck 1386
249     lscp_server_info_t* pServerInfo =
250     ::lscp_get_server_info(pMainForm->client());
251 capela 1394 if (pServerInfo && pServerInfo->protocol_version)
252 schoenebeck 1402 ::sscanf(pServerInfo->protocol_version, "%d.%d",
253     &result.major, &result.minor);
254 schoenebeck 1386
255     return result;
256     }
257 schoenebeck 1402
258     } // namespace qsamplerUtilities
259 capela 1464
260    
261     // end of qsamplerUtilities.cpp

  ViewVC Help
Powered by ViewVC