~ubuntu-branches/ubuntu/wily/kbibtex/wily

« back to all changes in this revision

Viewing changes to src/libkbibtexio/encoderlatex.cpp

  • Committer: Package Import Robot
  • Author(s): Michael Hanke
  • Date: 2011-07-18 09:29:48 UTC
  • mfrom: (1.1.6) (2.1.5 sid)
  • Revision ID: package-import@ubuntu.com-20110718092948-ksxjmg7kdfamolmg
Tags: 0.3-1
* First upstream release for KDE4 (Closes: #634255). A number of search
  engines are still missing, in comparison to the 0.2 series.
* Bumped Standards-Version to 3.9.2, no changes necessary.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
*   Copyright (C) 2004-2010 by Thomas Fischer                             *
 
3
*   fischer@unix-ag.uni-kl.de                                             *
 
4
*                                                                         *
 
5
*   This program is free software; you can redistribute it and/or modify  *
 
6
*   it under the terms of the GNU General Public License as published by  *
 
7
*   the Free Software Foundation; either version 2 of the License, or     *
 
8
*   (at your option) any later version.                                   *
 
9
*                                                                         *
 
10
*   This program is distributed in the hope that it will be useful,       *
 
11
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
12
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
13
*   GNU General Public License for more details.                          *
 
14
*                                                                         *
 
15
*   You should have received a copy of the GNU General Public License     *
 
16
*   along with this program; if not, write to the                         *
 
17
*   Free Software Foundation, Inc.,                                       *
 
18
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 
19
***************************************************************************/
 
20
#include <QString>
 
21
#include <QRegExp>
 
22
#include <QStringList>
 
23
#include <QList>
 
24
 
 
25
#include <KDebug>
 
26
 
 
27
#include "encoderlatex.h"
 
28
 
 
29
EncoderLaTeX *encoderLaTeX = NULL;
 
30
 
 
31
static struct Decomposition {
 
32
    const char *latexCommand;
 
33
    unsigned int unicode;
 
34
}
 
35
 
 
36
decompositions[] = {
 
37
    {"`", 0x0300},
 
38
    {"'", 0x0301},
 
39
    {"^", 0x0302},
 
40
    {"~", 0x0303},
 
41
    {"=", 0x0304},
 
42
    /*{"x", 0x0305},  OVERLINE */
 
43
    {"u", 0x0306},
 
44
    {".", 0x0307},
 
45
    /*{"x", 0x0309},  HOOK ABOVE */
 
46
    {"r", 0x030a},
 
47
    {"H", 0x030b},
 
48
    {"v", 0x030c},
 
49
    /*{"x", 0x030d},  VERTICAL LINE ABOVE */
 
50
    /*{"x", 0x030e},  DOUBLE VERTICAL LINE ABOVE */
 
51
    /*{"x", 0x030f},  DOUBLE GRAVE ACCENT */
 
52
    /*{"x", 0x0310},  CANDRABINDU */
 
53
    /*{"x", 0x0311},  INVERTED BREVE */
 
54
    /*{"x", 0x0312},  TURNED COMMA ABOVE */
 
55
    /*{"x", 0x0313},  COMMA ABOVE */
 
56
    /*{"x", 0x0314},  REVERSED COMMA ABOVE */
 
57
    /*{"x", 0x0315},   */
 
58
    /*{"x", 0x0316},   */
 
59
    /*{"x", 0x0317},   */
 
60
    /*{"x", 0x0318},   */
 
61
    /*{"x", 0x0319},   */
 
62
    /*{"x", 0x031a},   */
 
63
    /*{"x", 0x031b},   */
 
64
    /*{"x", 0x031c},   */
 
65
    /*{"x", 0x031d},   */
 
66
    /*{"x", 0x031e},   */
 
67
    /*{"x", 0x031f},   */
 
68
    /*{"x", 0x0320},   */
 
69
    /*{"x", 0x0321},   */
 
70
    /*{"x", 0x0322},   */
 
71
    {"d", 0x0323},
 
72
    /*{"x", 0x0324},   */
 
73
    /*{"x", 0x0325},   */
 
74
    /*{"x", 0x0326},   */
 
75
    {"d", 0x0327},
 
76
    {"k", 0x0328},
 
77
    /*{"x", 0x0329},   */
 
78
    /*{"x", 0x032a},   */
 
79
    /*{"x", 0x032b},   */
 
80
    /*{"x", 0x032c},   */
 
81
    /*{"x", 0x032d},   */
 
82
    /*{"x", 0x032e},   */
 
83
    /*{"x", 0x032f},   */
 
84
    {"b", 0x0331},
 
85
    {"t", 0x0361}
 
86
};
 
87
 
 
88
static const int decompositionscount = sizeof(decompositions) / sizeof(decompositions[ 0 ]) ;
 
89
 
 
90
static const struct EncoderLaTeXCommandMapping {
 
91
    const char *letters;
 
92
    unsigned int unicode;
 
93
}
 
94
commandmappingdatalatex[] = {
 
95
    {"AA", 0x00C5},
 
96
    {"AE", 0x00C6},
 
97
    {"ss", 0x00DF},
 
98
    {"aa", 0x00E5},
 
99
    {"ae", 0x00E6},
 
100
    {"OE", 0x0152},
 
101
    {"oe", 0x0153},
 
102
    {"ldots", 0x2026}, /** \ldots must be before \l */
 
103
    {"L", 0x0141},
 
104
    {"l", 0x0142},
 
105
    {"grqq", 0x201C},
 
106
    {"rqq", 0x201D},
 
107
    {"glqq", 0x201E},
 
108
    {"frqq", 0x00BB},
 
109
    {"flqq", 0x00AB},
 
110
    {"rq", 0x2019},
 
111
    {"lq", 0x2018}
 
112
};
 
113
 
 
114
static const int commandmappingdatalatexcount = sizeof(commandmappingdatalatex) / sizeof(commandmappingdatalatex[ 0 ]) ;
 
115
 
 
116
/** Command can be either
 
117
    (1) {embraced}
 
118
    (2) delimited by {},
 
119
    (3) <space>, line end,
 
120
    (4) \following_command (including \<space>, which must be maintained!),
 
121
    (5) } (end of entry or group)
 
122
 **/
 
123
const char *expansionsCmd[] = {"\\{\\\\%1\\}", "\\\\%1\\{\\}", "\\\\%1(\\n|\\r|\\\\|\\})", "\\\\%1\\s"};
 
124
static const  int expansionscmdcount = sizeof(expansionsCmd) / sizeof(expansionsCmd[0]);
 
125
 
 
126
static const struct EncoderLaTeXModCharMapping {
 
127
    const char *modifier;
 
128
    const char *letter;
 
129
    unsigned int unicode;
 
130
}
 
131
modcharmappingdatalatex[] = {
 
132
    {"\\\\`", "A", 0x00C0},
 
133
    {"\\\\'", "A", 0x00C1},
 
134
    {"\\\\\\^", "A", 0x00C2},
 
135
    {"\\\\~", "A", 0x00C3},
 
136
    {"\\\\\"", "A", 0x00C4},
 
137
    {"\\\\r", "A", 0x00C5},
 
138
    /** 0x00C6 */
 
139
    {"\\\\c", "C", 0x00C7},
 
140
    {"\\\\`", "E", 0x00C8},
 
141
    {"\\\\'", "E", 0x00C9},
 
142
    {"\\\\\\^", "E", 0x00CA},
 
143
    {"\\\\\"", "E", 0x00CB},
 
144
    {"\\\\`", "I", 0x00CC},
 
145
    {"\\\\'", "I", 0x00CD},
 
146
    {"\\\\\\^", "I", 0x00CE},
 
147
    {"\\\\\"", "I", 0x00CF},
 
148
    /** 0x00D0 */
 
149
    {"\\\\~", "N", 0x00D1},
 
150
    {"\\\\`", "O", 0x00D2},
 
151
    {"\\\\'", "O", 0x00D3},
 
152
    {"\\\\\\^", "O", 0x00D4},
 
153
    /** 0x00D5 */
 
154
    {"\\\\\"", "O", 0x00D6},
 
155
    /** 0x00D7 */
 
156
    {"\\\\", "O", 0x00D8},
 
157
    {"\\\\`", "U", 0x00D9},
 
158
    {"\\\\'", "U", 0x00DA},
 
159
    {"\\\\\\^", "U", 0x00DB},
 
160
    {"\\\\\"", "U", 0x00DC},
 
161
    {"\\\\'", "Y", 0x00DD},
 
162
    /** 0x00DE */
 
163
    {"\\\\\"", "s", 0x00DF},
 
164
    {"\\\\`", "a", 0x00E0},
 
165
    {"\\\\'", "a", 0x00E1},
 
166
    {"\\\\\\^", "a", 0x00E2},
 
167
    {"\\\\~", "a", 0x00E3},
 
168
    {"\\\\\"", "a", 0x00E4},
 
169
    {"\\\\r", "a", 0x00E5},
 
170
    /** 0x00E6 */
 
171
    {"\\\\c", "c", 0x00E7},
 
172
    {"\\\\`", "e", 0x00E8},
 
173
    {"\\\\'", "e", 0x00E9},
 
174
    {"\\\\\\^", "e", 0x00EA},
 
175
    {"\\\\\"", "e", 0x00EB},
 
176
    {"\\\\`", "i", 0x00EC},
 
177
    {"\\\\'", "i", 0x00ED},
 
178
    {"\\\\'", "\\\\i", 0x00ED},
 
179
    {"\\\\\\^", "i", 0x00EE},
 
180
    /** 0x00EF */
 
181
    /** 0x00F0 */
 
182
    {"\\\\~", "n", 0x00F1},
 
183
    {"\\\\`", "o", 0x00F2},
 
184
    {"\\\\'", "o", 0x00F3},
 
185
    {"\\\\\\^", "o", 0x00F4},
 
186
    /** 0x00F5 */
 
187
    {"\\\\\"", "o", 0x00F6},
 
188
    /** 0x00F7 */
 
189
    {"\\\\", "o", 0x00F8},
 
190
    {"\\\\`", "u", 0x00F9},
 
191
    {"\\\\'", "u", 0x00FA},
 
192
    {"\\\\\\^", "u", 0x00FB},
 
193
    {"\\\\\"", "u", 0x00FC},
 
194
    {"\\\\'", "y", 0x00FD},
 
195
    /** 0x00FE */
 
196
    /** 0x00FF */
 
197
    /** 0x0100 */
 
198
    /** 0x0101 */
 
199
    {"\\\\u", "A", 0x0102},
 
200
    {"\\\\u", "a", 0x0103},
 
201
    /** 0x0104 */
 
202
    /** 0x0105 */
 
203
    {"\\\\'", "C", 0x0106},
 
204
    {"\\\\'", "c", 0x0107},
 
205
    /** 0x0108 */
 
206
    /** 0x0109 */
 
207
    /** 0x010A */
 
208
    /** 0x010B */
 
209
    {"\\\\v", "C", 0x010C},
 
210
    {"\\\\v", "c", 0x010D},
 
211
    {"\\\\v", "D", 0x010E},
 
212
    /** 0x010F */
 
213
    /** 0x0110 */
 
214
    /** 0x0111 */
 
215
    /** 0x0112 */
 
216
    /** 0x0113 */
 
217
    /** 0x0114 */
 
218
    /** 0x0115 */
 
219
    /** 0x0116 */
 
220
    /** 0x0117 */
 
221
    {"\\\\c", "E", 0x0118},
 
222
    {"\\\\c", "e", 0x0119},
 
223
    {"\\\\v", "E", 0x011A},
 
224
    {"\\\\v", "e", 0x011B},
 
225
    /** 0x011C */
 
226
    /** 0x011D */
 
227
    {"\\\\u", "G", 0x011E},
 
228
    {"\\\\u", "g", 0x011F},
 
229
    /** 0x0120 */
 
230
    /** 0x0121 */
 
231
    /** 0x0122 */
 
232
    /** 0x0123 */
 
233
    /** 0x0124 */
 
234
    /** 0x0125 */
 
235
    /** 0x0126 */
 
236
    /** 0x0127 */
 
237
    /** 0x0128 */
 
238
    /** 0x0129 */
 
239
    /** 0x012A */
 
240
    /** 0x012B */
 
241
    {"\\\\u", "I", 0x012C},
 
242
    {"\\\\u", "i", 0x012D},
 
243
    /** 0x012E */
 
244
    /** 0x012F */
 
245
    /** 0x0130 */
 
246
    /** 0x0131 */
 
247
    /** 0x0132 */
 
248
    /** 0x0133 */
 
249
    /** 0x0134 */
 
250
    /** 0x0135 */
 
251
    /** 0x0136 */
 
252
    /** 0x0137 */
 
253
    /** 0x0138 */
 
254
    {"\\\\'", "L", 0x0139},
 
255
    {"\\\\'", "l", 0x013A},
 
256
    /** 0x013B */
 
257
    /** 0x013C */
 
258
    /** 0x013D */
 
259
    /** 0x013E */
 
260
    /** 0x013F */
 
261
    /** 0x0140 */
 
262
    /** 0x0141 */
 
263
    /** 0x0142 */
 
264
    {"\\\\'", "N", 0x0143},
 
265
    {"\\\\'", "n", 0x0144},
 
266
    /** 0x0145 */
 
267
    /** 0x0146 */
 
268
    {"\\\\v", "N", 0x0147},
 
269
    {"\\\\v", "n", 0x0148},
 
270
    /** 0x0149 */
 
271
    /** 0x014A */
 
272
    /** 0x014B */
 
273
    /** 0x014C */
 
274
    /** 0x014D */
 
275
    {"\\\\u", "O", 0x014E},
 
276
    {"\\\\u", "o", 0x014F},
 
277
    {"\\\\H", "O", 0x0150},
 
278
    {"\\\\H", "o", 0x0151},
 
279
    /** 0x0152 */
 
280
    /** 0x0153 */
 
281
    {"\\\\'", "R", 0x0154},
 
282
    {"\\\\'", "r", 0x0155},
 
283
    /** 0x0156 */
 
284
    /** 0x0157 */
 
285
    {"\\\\v", "R", 0x0158},
 
286
    {"\\\\v", "r", 0x0159},
 
287
    {"\\\\'", "S", 0x015A},
 
288
    {"\\\\'", "s", 0x015B},
 
289
    /** 0x015C */
 
290
    /** 0x015D */
 
291
    {"\\\\c", "S", 0x015E},
 
292
    {"\\\\c", "s", 0x015F},
 
293
    {"\\\\v", "S", 0x0160},
 
294
    {"\\\\v", "s", 0x0161},
 
295
    /** 0x0162 */
 
296
    /** 0x0163 */
 
297
    {"\\\\v", "T", 0x0164},
 
298
    /** 0x0165 */
 
299
    /** 0x0166 */
 
300
    /** 0x0167 */
 
301
    /** 0x0168 */
 
302
    /** 0x0169 */
 
303
    /** 0x016A */
 
304
    /** 0x016B */
 
305
    {"\\\\u", "U", 0x016C},
 
306
    {"\\\\u", "u", 0x016D},
 
307
    {"\\\\r", "U", 0x016E},
 
308
    {"\\\\r", "u", 0x016F},
 
309
    /** 0x0170 */
 
310
    /** 0x0171 */
 
311
    /** 0x0172 */
 
312
    /** 0x0173 */
 
313
    /** 0x0174 */
 
314
    /** 0x0175 */
 
315
    /** 0x0176 */
 
316
    /** 0x0177 */
 
317
    {"\\\\\"", "Y", 0x0178},
 
318
    {"\\\\'", "Z", 0x0179},
 
319
    {"\\\\'", "z", 0x017A},
 
320
    /** 0x017B */
 
321
    /** 0x017C */
 
322
    {"\\\\v", "Z", 0x017D},
 
323
    {"\\\\v", "z", 0x017E},
 
324
    /** 0x017F */
 
325
    /** 0x0180 */
 
326
    {"\\\\v", "A", 0x01CD},
 
327
    {"\\\\v", "a", 0x01CE},
 
328
    {"\\\\v", "G", 0x01E6},
 
329
    {"\\\\v", "g", 0x01E7}
 
330
};
 
331
 
 
332
const char *expansionsMod1[] = {"\\{%1\\{%2\\}\\}", "\\{%1 %2\\}", "%1\\{%2\\}"};
 
333
static const  int expansionsmod1count = sizeof(expansionsMod1) / sizeof(expansionsMod1[0]);
 
334
const char *expansionsMod2[] = {"\\{%1%2\\}", "%1%2\\{\\}", "%1%2"};
 
335
static const  int expansionsmod2count = sizeof(expansionsMod2) / sizeof(expansionsMod2[0]);
 
336
 
 
337
static const int modcharmappingdatalatexcount = sizeof(modcharmappingdatalatex) / sizeof(modcharmappingdatalatex[ 0 ]) ;
 
338
 
 
339
static const struct EncoderLaTeXCharMapping {
 
340
    const char *regexp;
 
341
    unsigned int unicode;
 
342
    const char *latex;
 
343
}
 
344
charmappingdatalatex[] = {
 
345
    {"\\\\#", 0x0023, "\\#"},
 
346
    {"\\\\&", 0x0026, "\\&"},
 
347
    {"\\\\_", 0x005F, "\\_"},
 
348
    {"!`", 0x00A1, "!`"},
 
349
    {"\"<", 0x00AB, "\"<"},
 
350
    {"\">", 0x00BB, "\">"},
 
351
    {"[?]`", 0x00BF, "?`"},
 
352
    {"---", 0x2014, "---"}, ///< has to be befor 0x2013, otherwise it would be interpreted as --{}-
 
353
    {"--", 0x2013, "--"},
 
354
    {"``", 0x201C, "``"},
 
355
    {"''", 0x201D, "''"}
 
356
};
 
357
 
 
358
static const int charmappingdatalatexcount = sizeof(charmappingdatalatex) / sizeof(charmappingdatalatex[ 0 ]) ;
 
359
 
 
360
/**
 
361
 * Private class to store internal variables that should not be visible
 
362
 * in the interface as defined in the header file.
 
363
 */
 
364
class EncoderLaTeX::EncoderLaTeXPrivate
 
365
{
 
366
public:
 
367
    struct CombinedMappingItem {
 
368
        QRegExp regExp;
 
369
        QString latex;
 
370
    };
 
371
 
 
372
    struct CharMappingItem {
 
373
        QRegExp regExp;
 
374
        QString unicode;
 
375
        QString latex;
 
376
    };
 
377
 
 
378
    QList<CombinedMappingItem> combinedMapping;
 
379
    QList<CharMappingItem> charMapping;
 
380
 
 
381
    void buildCombinedMapping() {
 
382
        for (int i = 0; i < decompositionscount; i++) {
 
383
            CombinedMappingItem item;
 
384
            item.regExp = QRegExp("(.)" + QString(QChar(decompositions[i].unicode)));
 
385
            item.latex = decompositions[i].latexCommand;
 
386
            combinedMapping.append(item);
 
387
        }
 
388
    }
 
389
 
 
390
    void buildCharMapping() {
 
391
        /** encoding and decoding for digraphs such as -- or ?` */
 
392
        for (int i = 0; i < charmappingdatalatexcount; i++) {
 
393
            CharMappingItem charMappingItem;
 
394
            charMappingItem.regExp = QRegExp(charmappingdatalatex[ i ].regexp);
 
395
            charMappingItem.unicode = QChar(charmappingdatalatex[ i ].unicode);
 
396
            charMappingItem.latex = QString(charmappingdatalatex[ i ].latex);
 
397
            charMapping.append(charMappingItem);
 
398
        }
 
399
 
 
400
        /** encoding and decoding for commands such as \AA or \ss */
 
401
        for (int i = 0; i < commandmappingdatalatexcount; ++i) {
 
402
            /** different types of writing such as {\AA} or \AA{} possible */
 
403
            for (int j = 0; j < expansionscmdcount; ++j) {
 
404
                CharMappingItem charMappingItem;
 
405
                charMappingItem.regExp = QRegExp(QString(expansionsCmd[j]).arg(commandmappingdatalatex[i].letters));
 
406
                charMappingItem.unicode = QChar(commandmappingdatalatex[i].unicode);
 
407
                if (charMappingItem.regExp.numCaptures() > 0)
 
408
                    charMappingItem.unicode += QString("\\1");
 
409
                charMappingItem.latex = QString("{\\%1}").arg(commandmappingdatalatex[i].letters);
 
410
                charMapping.append(charMappingItem);
 
411
            }
 
412
        }
 
413
 
 
414
        /** encoding and decoding for letters such as \"a */
 
415
        for (int i = 0; i < modcharmappingdatalatexcount; ++i) {
 
416
            QString modifierRegExp = QString(modcharmappingdatalatex[i].modifier);
 
417
            QString modifier = modifierRegExp;
 
418
            modifier.replace("\\^", "^").replace("\\\\", "\\");
 
419
 
 
420
            /** first batch of replacement rules, where no separator is required between modifier and character (e.g. \"a) */
 
421
            if (!modifierRegExp.at(modifierRegExp.length() - 1).isLetter())
 
422
                for (int j = 0; j < expansionsmod2count; ++j) {
 
423
                    CharMappingItem charMappingItem;
 
424
                    charMappingItem.regExp = QRegExp(QString(expansionsMod2[j]).arg(modifierRegExp).arg(modcharmappingdatalatex[i].letter));
 
425
                    charMappingItem.unicode = QChar(modcharmappingdatalatex[i].unicode);
 
426
                    charMappingItem.latex = QString("{%1%2}").arg(modifier).arg(modcharmappingdatalatex[i].letter);
 
427
                    charMapping.append(charMappingItem);
 
428
                }
 
429
 
 
430
            /** second batch of replacement rules, where a separator is required between modifier and character (e.g. \v{g}) */
 
431
            for (int j = 0; j < expansionsmod1count; ++j) {
 
432
                CharMappingItem charMappingItem;
 
433
                charMappingItem.regExp = QRegExp(QString(expansionsMod1[j]).arg(modifierRegExp).arg(modcharmappingdatalatex[i].letter));
 
434
                charMappingItem.unicode = QChar(modcharmappingdatalatex[i].unicode);
 
435
                charMappingItem.latex = QString("%1{%2}").arg(modifier).arg(modcharmappingdatalatex[i].letter);
 
436
                charMapping.append(charMappingItem);
 
437
            }
 
438
        }
 
439
    }
 
440
};
 
441
 
 
442
EncoderLaTeX::EncoderLaTeX()
 
443
        : Encoder(), d(new EncoderLaTeX::EncoderLaTeXPrivate)
 
444
{
 
445
    d->buildCharMapping();
 
446
    d->buildCombinedMapping();
 
447
}
 
448
 
 
449
EncoderLaTeX::~EncoderLaTeX()
 
450
{
 
451
    // nothing
 
452
}
 
453
 
 
454
QString EncoderLaTeX::decode(const QString & text)
 
455
{
 
456
    const QString splitMarker = "|KBIBTEX|";
 
457
 
 
458
    /** start-stop marker ensures that each text starts and stops
 
459
      * with plain text and not with an inline math environment.
 
460
      * This invariant is exploited implicitly in the code below. */
 
461
    const QString startStopMarker = "|STARTSTOP|";
 
462
    QString result = startStopMarker + text + startStopMarker;
 
463
 
 
464
    /** Collect (all?) urls from the BibTeX file and store them in urls */
 
465
    /** Problem is that the replace function below will replace
 
466
      * character sequences in the URL rendering the URL invalid.
 
467
      * Later, all URLs will be replaced back to their original
 
468
      * in the hope nothing breaks ... */
 
469
    QStringList urls;
 
470
    QRegExp httpRegExp("(ht|f)tps?://[^\"} ]+");
 
471
    httpRegExp.setMinimal(false);
 
472
    int pos = 0;
 
473
    while (pos >= 0) {
 
474
        pos = result.indexOf(httpRegExp, pos);
 
475
        if (pos >= 0) {
 
476
            ++pos;
 
477
            QString url = httpRegExp.cap(0);
 
478
            urls << url;
 
479
        }
 
480
    }
 
481
 
 
482
    decomposedUTF8toLaTeX(result);
 
483
 
 
484
    /** split text into math and non-math regions */
 
485
    QStringList intermediate = result.split('$', QString::SkipEmptyParts);
 
486
    QStringList::Iterator it = intermediate.begin();
 
487
    while (it != intermediate.end()) {
 
488
        /**
 
489
         * Sometimes we split strings like "\$", which is not intended.
 
490
         * So, we have to manually fix things by checking for strings
 
491
         * ending with "\" and append both the removed dollar sign and
 
492
         * the following string (which was never supposed to be an
 
493
         * independent string). Finally, we remove the unnecessary
 
494
         * string and continue.
 
495
         */
 
496
        if ((*it).endsWith("\\")) {
 
497
            QStringList::Iterator cur = it;
 
498
            ++it;
 
499
            (*cur).append('$').append(*it);
 
500
            it = intermediate.erase(it);
 
501
        } else
 
502
            ++it;
 
503
    }
 
504
 
 
505
    result = "";
 
506
    for (QStringList::Iterator it = intermediate.begin(); it != intermediate.end(); ++it) {
 
507
        if (!result.isEmpty()) result.append(splitMarker);
 
508
        result.append(*it);
 
509
 
 
510
        // skip math regions
 
511
        ++it;
 
512
 
 
513
        if (it == intermediate.end())
 
514
            break;
 
515
 
 
516
        if ((*it).length() > 256)
 
517
            kWarning() << "Very long math equation using $ found, maybe due to broken inline math: " << (*it).left(48);
 
518
    }
 
519
 
 
520
    for (QList<EncoderLaTeXPrivate::CharMappingItem>::ConstIterator cmit = d->charMapping.begin(); cmit != d->charMapping.end(); ++cmit)
 
521
        result.replace((*cmit).regExp, (*cmit).unicode);
 
522
    QStringList transformed = result.split(splitMarker, QString::SkipEmptyParts);
 
523
 
 
524
    result = "";
 
525
    for (QStringList::Iterator itt = transformed.begin(), iti = intermediate.begin(); itt != transformed.end() && iti != intermediate.end(); ++itt, ++iti) {
 
526
        result.append(*itt);
 
527
 
 
528
        ++iti;
 
529
        if (iti == intermediate.end())
 
530
            break;
 
531
 
 
532
        result.append("$").append(*iti).append("$");
 
533
    }
 
534
 
 
535
    /** Reinserting original URLs as explained above */
 
536
    pos = 0;
 
537
    int idx = 0;
 
538
    while (pos >= 0) {
 
539
        pos = result.indexOf(httpRegExp, pos);
 
540
        if (pos >= 0) {
 
541
            ++pos;
 
542
            int len = httpRegExp.cap(0).length();
 
543
            result = result.left(pos - 1).append(urls[idx++]).append(result.mid(pos + len - 1));
 
544
        }
 
545
    }
 
546
 
 
547
    return result.replace(startStopMarker, "");
 
548
}
 
549
 
 
550
QString EncoderLaTeX::encode(const QString & text)
 
551
{
 
552
    const QString splitMarker = "|KBIBTEX|";
 
553
 
 
554
    /** start-stop marker ensures that each text starts and stops
 
555
      * with plain text and not with an inline math environment.
 
556
      * This invariant is exploited implicitly in the code below. */
 
557
    const QString startStopMarker = "|STARTSTOP|";
 
558
    QString result = startStopMarker + text + startStopMarker;
 
559
 
 
560
    /** Collect (all?) urls from the BibTeX file and store them in urls */
 
561
    /** Problem is that the replace function below will replace
 
562
      * character sequences in the URL rendering the URL invalid.
 
563
      * Later, all URLs will be replaced back to their original
 
564
      * in the hope nothing breaks ... */
 
565
    QStringList urls;
 
566
    QRegExp httpRegExp("(ht|f)tps?://[^\"} ]+");
 
567
    httpRegExp.setMinimal(false);
 
568
    int pos = 0;
 
569
    while (pos >= 0) {
 
570
        pos = result.indexOf(httpRegExp, pos);
 
571
        if (pos >= 0) {
 
572
            ++pos;
 
573
            QString url = httpRegExp.cap(0);
 
574
            urls << url;
 
575
        }
 
576
    }
 
577
 
 
578
    /** split text into math and non-math regions */
 
579
    QStringList intermediate = result.split('$', QString::SkipEmptyParts);
 
580
    QStringList::Iterator it = intermediate.begin();
 
581
    while (it != intermediate.end()) {
 
582
        /**
 
583
         * Sometimes we split strings like "\$", which is not intended.
 
584
         * So, we have to manually fix things by checking for strings
 
585
         * ending with "\" and append both the removed dollar sign and
 
586
         * the following string (which was never supposed to be an
 
587
         * independent string). Finally, we remove the unnecessary
 
588
         * string and continue.
 
589
         */
 
590
        if ((*it).endsWith("\\")) {
 
591
            QStringList::Iterator cur = it;
 
592
            ++it;
 
593
            (*cur).append('$').append(*it);
 
594
            it = intermediate.erase(it);
 
595
        } else
 
596
            ++it;
 
597
    }
 
598
 
 
599
    result = "";
 
600
    for (QStringList::Iterator it = intermediate.begin(); it != intermediate.end(); ++it) {
 
601
        if (!result.isEmpty()) result.append(splitMarker);
 
602
        result.append(*it);
 
603
        ++it;
 
604
        if (it == intermediate.end())
 
605
            break;
 
606
        if ((*it).length() > 256)
 
607
            qDebug() << "Very long math equation using $ found, maybe due to broken inline math:" << (*it).left(48) << endl;
 
608
    }
 
609
 
 
610
    for (QList<EncoderLaTeXPrivate::CharMappingItem>::ConstIterator cmit = d->charMapping.begin(); cmit != d->charMapping.end(); ++cmit)
 
611
        result.replace((*cmit).unicode, (*cmit).latex);
 
612
 
 
613
    QStringList transformed = result.split(splitMarker, QString::KeepEmptyParts, Qt::CaseSensitive);
 
614
 
 
615
    result = "";
 
616
    for (QStringList::Iterator itt = transformed.begin(), iti = intermediate.begin(); itt != transformed.end() && iti != intermediate.end(); ++itt, ++iti) {
 
617
        result.append(*itt);
 
618
 
 
619
        ++iti;
 
620
        if (iti == intermediate.end())
 
621
            break;
 
622
 
 
623
        result.append("$").append(*iti).append("$");
 
624
    }
 
625
 
 
626
    /** \url accepts unquotet & and _
 
627
    May introduce new problem tough */
 
628
    if (result.contains("\\url{"))
 
629
        result.replace("\\&", "&").replace("\\_", "_").replace(QChar(0x2013), "--").replace("\\#", "#");
 
630
 
 
631
    decomposedUTF8toLaTeX(result);
 
632
 
 
633
    /** Reinserting original URLs as explained above */
 
634
    pos = 0;
 
635
    int idx = 0;
 
636
    while (pos >= 0) {
 
637
        pos = result.indexOf(httpRegExp, pos);
 
638
        if (pos >= 0) {
 
639
            ++pos;
 
640
            int len = httpRegExp.cap(0).length();
 
641
            result = result.left(pos - 1).append(urls[idx++]).append(result.mid(pos + len - 1));
 
642
        }
 
643
    }
 
644
 
 
645
    return result.replace(startStopMarker, "");
 
646
}
 
647
 
 
648
QString EncoderLaTeX::encode(const QString &text, const QChar &replace)
 
649
{
 
650
    QString result = text;
 
651
    for (QList<EncoderLaTeXPrivate::CharMappingItem>::ConstIterator it = d->charMapping.begin(); it != d->charMapping.end(); ++it)
 
652
        if ((*it).unicode == replace)
 
653
            result.replace((*it).unicode, (*it).latex);
 
654
    return result;
 
655
}
 
656
 
 
657
QString& EncoderLaTeX::decomposedUTF8toLaTeX(QString &text)
 
658
{
 
659
    for (QList<EncoderLaTeXPrivate::CombinedMappingItem>::Iterator it = d->combinedMapping.begin(); it != d->combinedMapping.end(); ++it) {
 
660
        int i = (*it).regExp.indexIn(text);
 
661
        while (i >= 0) {
 
662
            QString a = (*it).regExp.cap(1);
 
663
            text = text.left(i) + "\\" + (*it).latex + "{" + a + "}" + text.mid(i + 2);
 
664
            i = (*it).regExp.indexIn(text, i + 1);
 
665
        }
 
666
    }
 
667
 
 
668
    return text;
 
669
}
 
670
 
 
671
 
 
672
EncoderLaTeX* EncoderLaTeX::currentEncoderLaTeX()
 
673
{
 
674
    if (encoderLaTeX == NULL)
 
675
        encoderLaTeX = new EncoderLaTeX();
 
676
 
 
677
    return encoderLaTeX;
 
678
}
 
679
 
 
680
void EncoderLaTeX::deleteCurrentEncoderLaTeX()
 
681
{
 
682
    if (encoderLaTeX != NULL) {
 
683
        delete encoderLaTeX;
 
684
        encoderLaTeX = NULL;
 
685
    }
 
686
}
 
687
 
 
688
QString& EncoderLaTeX::convertToPlainAscii(QString &text)
 
689
{
 
690
    for (int i = 0; i < modcharmappingdatalatexcount; ++i) {
 
691
        QChar c = QChar(modcharmappingdatalatex[i].unicode);
 
692
        if (text.indexOf(c) >= 0)
 
693
            text = text.replace(c, QString(modcharmappingdatalatex[i].letter));
 
694
    }
 
695
    for (int i = 0; i < commandmappingdatalatexcount; ++i) {
 
696
        QChar c = QChar(commandmappingdatalatex[i].unicode);
 
697
        if (text.indexOf(c) >= 0)
 
698
            text = text.replace(c, QString(commandmappingdatalatex[i].letters));
 
699
    }
 
700
 
 
701
    return text;
 
702
}