filters

ailexer.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002, Dirk Schönberger <dirk.schoenberger@sz-online.de>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <ctype.h>
21#include <stdlib.h>
22#include <tqstringlist.h>
23#include "ailexer.h"
24
25#define CATEGORY_WHITESPACE -1
26#define CATEGORY_ALPHA -2
27#define CATEGORY_DIGIT -3
28#define CATEGORY_SPECIAL -4
29#define CATEGORY_LETTERHEX -5
30#define CATEGORY_INTTOOLONG -6
31
32#define CATEGORY_ANY -127
33
34#define MAX_INTLEN 9
35#define MIN_HEXCHARS 6
36
37#define STOP 0
38
39int iswhitespace(char c){
40 return (c==' ')||(c=='\n')||(c=='\t')||(c=='\r');
41}
42
43int isSpecial(char c){
44 return (c=='*')||(c=='_')||(c=='?')||(c=='~')||(c=='-')||(c=='^')||(c=='`')||(c=='!')||(c=='.')||(c=='@')||(c=='&')||(c=='$')||(c=='=');
45}
46
47int isletterhex(char c){
48 return (c=='A')||(c=='B')||(c=='C')||(c=='D')||(c=='E')||(c=='F');
49}
50
51const char*statetoa (State state){
52 switch (state)
53 {
54 case State_Comment : return "comment";
55 case State_Integer : return "integer";
56 case State_Float : return "float";
57 case State_String : return "string";
58 case State_Token : return "token";
59 case State_Reference : return "reference";
60 case State_Start : return "start";
61 case State_BlockStart : return "block start";
62 case State_BlockEnd : return "block end";
63 case State_ArrayStart : return "array start";
64 case State_ArrayEnd : return "array end";
65 case State_Byte : return "byte";
66 case State_ByteArray : return "byte array";
67 case State_StringEncodedChar : return "encoded char (string)";
68 case State_CommentEncodedChar : return "encoded char (comment)";
69 case State_ByteArray2 : return "byte array (mode 2)";
70 default : return "unknown";
71 }
72}
73
74typedef struct {
75 State oldState;
76 signed char c;
77 State newState;
78 Action action;
79} Transition;
80
81static Transition transitions[] = {
82 { State_Comment, '\n', State_Start, Action_Output},
83 { State_Comment, '\r', State_Start, Action_Output},
84 { State_Comment, '\\', State_CommentEncodedChar, Action_InitTemp},
85 { State_Comment, CATEGORY_ANY, State_Comment, Action_Copy},
86 { State_Integer, CATEGORY_DIGIT, State_Integer, Action_Copy},
87 { State_Integer, CATEGORY_WHITESPACE, State_Start, Action_Output},
88 { State_Integer, '.', State_Float, Action_Copy},
89 { State_Integer, ']', State_Start, Action_OutputUnget},
90 { State_Integer, '}', State_Start, Action_OutputUnget},
91 { State_Integer, '#', State_Byte, Action_Copy },
92 { State_Integer, '/', State_Start, Action_OutputUnget },
93 { State_Integer, '{', State_Start, Action_OutputUnget },
94 { State_Integer, '%', State_Start, Action_OutputUnget },
95 { State_Integer, CATEGORY_LETTERHEX, State_ByteArray2, Action_Copy },
96 { State_Integer, CATEGORY_INTTOOLONG, State_ByteArray2, Action_Copy },
97 { State_Integer, CATEGORY_ANY, State_Start, Action_Abort},
98 { State_Float, CATEGORY_DIGIT, State_Float, Action_Copy},
99 { State_Float, CATEGORY_WHITESPACE, State_Start, Action_Output},
100 { State_Float, ']', State_Start, Action_OutputUnget},
101 { State_Float, '}', State_Start, Action_OutputUnget},
102 { State_Float, CATEGORY_ANY, State_Start, Action_Abort},
103 { State_Token, CATEGORY_ALPHA, State_Token, Action_Copy},
104 { State_Token, CATEGORY_DIGIT, State_Token, Action_Copy},
105 { State_Token, CATEGORY_SPECIAL, State_Token, Action_Copy},
106 { State_Token, '}', State_Start, Action_OutputUnget},
107 { State_Token, ']', State_Start, Action_OutputUnget},
108 { State_Token, '{', State_BlockStart, Action_Output},
109 { State_Token, '}', State_BlockEnd, Action_Output},
110 { State_Token, '/', State_Start, Action_OutputUnget},
111 { State_Token, CATEGORY_WHITESPACE, State_Start, Action_Output},
112 { State_Token, CATEGORY_ANY, State_Start, Action_Abort},
113 { State_String, ')', State_Start, Action_Output},
114 { State_String, '\\', State_StringEncodedChar, Action_InitTemp},
115 { State_String, CATEGORY_ANY, State_String, Action_Copy},
116// { State_Array, CATEGORY_ALPHA, State_Array, Action_Copy},
117// { State_Array, CATEGORY_DIGIT, State_Array, Action_Copy},
118// { State_Array, ' ', State_Array, Action_Copy},
119 { State_BlockStart, CATEGORY_ANY, State_Start, Action_OutputUnget },
120 { State_BlockEnd, CATEGORY_ANY, State_Start, Action_OutputUnget },
121 { State_ArrayStart, CATEGORY_ANY, State_Start, Action_OutputUnget },
122 { State_ArrayEnd, CATEGORY_ANY, State_Start, Action_OutputUnget },
123 { State_Reference, '#', State_Reference, Action_Copy },
124 { State_Reference, CATEGORY_ALPHA, State_Reference, Action_Copy },
125 { State_Reference, CATEGORY_DIGIT, State_Reference, Action_Copy },
126 { State_Reference, CATEGORY_SPECIAL, State_Reference, Action_Copy },
127 { State_Reference, CATEGORY_ANY, State_Start, Action_OutputUnget },
128 { State_Byte, '/', State_Start, Action_OutputUnget },
129 { State_Byte, CATEGORY_DIGIT, State_Byte, Action_Copy},
130 { State_Byte, CATEGORY_ALPHA, State_Byte, Action_Copy},
131 { State_Byte, CATEGORY_WHITESPACE, State_Start, Action_Output},
132 { State_ByteArray, '>', State_Start, Action_Output },
133 { State_ByteArray, CATEGORY_ALPHA, State_ByteArray, Action_Copy },
134 { State_ByteArray, CATEGORY_DIGIT, State_ByteArray, Action_Copy },
135 { State_ByteArray, CATEGORY_WHITESPACE, State_ByteArray, Action_Ignore },
136 { State_ByteArray, CATEGORY_ANY, State_Start, Action_Abort },
137 { State_StringEncodedChar, '\\', State_String, Action_Copy},
138 { State_StringEncodedChar, CATEGORY_DIGIT, State_StringEncodedChar, Action_CopyTemp},
139 { State_StringEncodedChar, CATEGORY_ANY, State_String, Action_DecodeUnget},
140 { State_CommentEncodedChar, '\\', State_Comment, Action_Copy},
141 { State_CommentEncodedChar, CATEGORY_DIGIT, State_CommentEncodedChar, Action_CopyTemp},
142 { State_CommentEncodedChar, CATEGORY_ANY, State_Comment, Action_DecodeUnget},
143 { State_ByteArray2, '\n', State_Start, Action_Output},
144 { State_ByteArray2, '\r', State_Start, Action_Output},
145 { State_ByteArray2, '}', State_Start, Action_ByteArraySpecial},
146 { State_ByteArray2, CATEGORY_WHITESPACE, State_Start, Action_Output},
147 { State_ByteArray2, CATEGORY_DIGIT, State_ByteArray2, Action_Copy},
148 { State_ByteArray2, CATEGORY_LETTERHEX, State_ByteArray2, Action_Copy},
149 { State_ByteArray2, CATEGORY_ALPHA, State_Token, Action_Copy},
150 { State_ByteArray2, CATEGORY_ANY, State_Start, Action_Abort},
151 { State_Start, '%', State_Comment, Action_Ignore},
152 { State_Start, CATEGORY_DIGIT, State_Integer, Action_Copy},
153 { State_Start, '-', State_Integer, Action_Copy},
154 { State_Start, '+', State_Integer, Action_Copy},
155 { State_Start, '.', State_Float, Action_Copy},
156 { State_Start, '/', State_Reference, Action_Ignore },
157 { State_Start, '(', State_String, Action_Ignore},
158 { State_Start, '{', State_BlockStart, Action_Copy},
159 { State_Start, '}', State_BlockEnd, Action_Copy},
160 { State_Start, '[', State_ArrayStart, Action_Copy},
161 { State_Start, ']', State_ArrayEnd, Action_Copy},
162 { State_Start, '<', State_ByteArray, Action_Ignore},
163 { State_Start, CATEGORY_ALPHA, State_Token, Action_Copy},
164 { State_Start, CATEGORY_WHITESPACE, State_Start, Action_Output},
165 { State_Start, CATEGORY_SPECIAL, State_Token, Action_Copy},
166 { State_Start, CATEGORY_LETTERHEX, State_ByteArray2, Action_Copy},
167 { State_Start, CATEGORY_ANY, State_Start, Action_Abort},
168 { State_Start, STOP, State_Start, Action_Abort}
169};
170
171AILexer::AILexer(){
172}
173AILexer::~AILexer(){
174}
175
176bool AILexer::parse (TQIODevice& fin){
177 char c;
178
179 m_buffer.clear();
180 m_curState = State_Start;
181
182 parsingStarted();
183
184 while (!fin.atEnd())
185 {
186 c = fin.getch ();
187
188// tqDebug ("got %c", c);
189
190 State newState;
191 Action action;
192
193 nextStep (c, &newState, &action);
194
195 switch (action)
196 {
197 case Action_Copy :
198 m_buffer.append (c);
199 break;
200 case Action_CopyOutput :
201 m_buffer.append (c);
202 doOutput();
203 break;
204 case Action_Output :
205 doOutput();
206 break;
207 case Action_OutputUnget :
208 doOutput();
209 fin.ungetch(c);
210 break;
211 case Action_Ignore :
212 /* ignore */
213 break;
214 case Action_Abort :
215 tqWarning ( "state %s / %s char %c (%d)" , statetoa(m_curState), statetoa(newState), c, c );
216 parsingAborted();
217 return false;
218 break;
219 case Action_InitTemp :
220 m_temp.clear();
221 break;
222 case Action_CopyTemp :
223 m_temp.append (c);
224 break;
225 case Action_DecodeUnget :
226 m_buffer.append (decode());
227 fin.ungetch(c);
228 break;
229 // in Postscript Quelltext: Kombination F}
230 case Action_ByteArraySpecial :
231 m_curState = State_Token;
232 doOutput();
233 fin.ungetch(c);
234 break;
235 default :
236 tqWarning ( "unknown action: %d ", action);
237 }
238
239 m_curState = newState;
240 }
241
242 parsingFinished();
243 return true;
244}
245
246void AILexer::doOutput ()
247{
248 if (m_buffer.length() == 0) return;
249 switch (m_curState)
250 {
251 case State_Comment :
252 gotComment (m_buffer.latin1());
253 break;
254 case State_Integer :
255 gotIntValue (m_buffer.toInt());
256 break;
257 case State_Float :
258 gotDoubleValue (m_buffer.toFloat());
259 break;
260 case State_String :
261 gotStringValue (m_buffer.latin1());
262 break;
263 case State_Token :
264 gotToken (m_buffer.latin1());
265 break;
266 case State_Reference :
267 gotReference (m_buffer.latin1());
268 break;
269 case State_BlockStart :
270 gotBlockStart ();
271 break;
272 case State_BlockEnd :
273 gotBlockEnd ();
274 break;
275 case State_Start :
276 break;
277 case State_ArrayStart :
278 gotArrayStart ();
279 break;
280 case State_ArrayEnd :
281 gotArrayEnd ();
282 break;
283 case State_Byte :
284 gotByte (getByte());
285 break;
286 case State_ByteArray :
287 case State_ByteArray2 :
288 doHandleByteArray ();
289 break;
290 default:
291 tqWarning ( "unknown state: %d", m_curState );
292 }
293
294 m_buffer.clear();
295}
296
297void AILexer::gotComment (const char *value) {
298 tqDebug ( "gotComment: %s ", value );
299}
300
301void AILexer::gotIntValue (int value) {
302 tqDebug ( "gotInt: %d ", value );
303}
304
305void AILexer::gotDoubleValue (double value) {
306 tqDebug ( "gotDouble: %f ", value );
307}
308
309void AILexer::gotStringValue (const char *value) {
310 tqDebug ( "gotString: %s ", value );
311}
312
313void AILexer::gotToken (const char *value) {
314 tqDebug ( "gotToken: %s ", value );
315}
316
317void AILexer::gotReference (const char *value) {
318 tqDebug ( "gotReference: %s ", value );
319}
320
321void AILexer::gotBlockStart (){
322 tqDebug ( "gotBlockStart" );
323}
324
325void AILexer::gotBlockEnd (){
326 tqDebug ( "gotBlockEnd" );
327}
328
329void AILexer::gotArrayStart (){
330 tqDebug ( "gotArrayStart" );
331}
332
333void AILexer::gotArrayEnd (){
334 tqDebug ( "gotArrayEnd" );
335}
336
337void AILexer::parsingStarted() {
338 tqDebug ( "parsing started" );
339}
340
341void AILexer::parsingFinished() {
342 tqDebug ( "parsing finished" );
343}
344
345void AILexer::parsingAborted() {
346 tqDebug ( "parsing aborted" );
347}
348
349void AILexer::gotByte (uchar value) {
350 tqDebug ( "got byte %d" , value );
351}
352
353void AILexer::gotByteArray (const TQByteArray &data) {
354 tqDebug ( "got byte array" );
355/* for ( uint i = 0; i < data.size(); i++ )
356 {
357 uchar value = data[i];
358 tqDebug( "%d: %x", i, value );
359 }
360 tqDebug ( "/byte array" ); */
361
362}
363
364
365void AILexer::nextStep (char c, State *newState, Action *newAction) {
366 int i=0;
367
368 while (true) {
369 Transition trans = transitions[i];
370
371 if (trans.c == STOP) {
372 *newState = trans.newState;
373 *newAction = trans.action;
374 return;
375 }
376
377 bool found = false;
378
379 if (trans.oldState == m_curState) {
380 switch (trans.c) {
381 case CATEGORY_WHITESPACE : found = isspace(c); break;
382 case CATEGORY_ALPHA : found = isalpha(c); break;
383 case CATEGORY_DIGIT : found = isdigit(c); break;
384 case CATEGORY_SPECIAL : found = isSpecial(c); break;
385 case CATEGORY_LETTERHEX : found = isletterhex(c); break;
386 case CATEGORY_INTTOOLONG : found = m_buffer.length() > MAX_INTLEN; break;
387 case CATEGORY_ANY : found = true; break;
388 default : found = (trans.c == c);
389 }
390
391 if (found) {
392 *newState = trans.newState;
393 *newAction = trans.action;
394
395 return;
396 }
397 }
398
399
400 i++;
401 }
402}
403
404void AILexer::doHandleByteArray ()
405{
406 // Special case - too short
407 if (m_buffer.length () < MIN_HEXCHARS)
408 {
409 gotToken (m_buffer.latin1());
410 return;
411 }
412
413 uint strIdx = 0;
414 uint arrayIdx = 0;
415
416 TQByteArray data (m_buffer.length() >> 1);
417
418 while (strIdx < m_buffer.length())
419 {
420 const TQString &item = m_buffer.mid (strIdx, 2);
421 uchar val = item.toShort(NULL, 16);
422 data[arrayIdx] = val;
423 strIdx += 2;
424 arrayIdx++;
425 }
426
427 gotByteArray (data);
428}
429
430uchar AILexer::getByte()
431{
432// tqDebug ("convert string to byte (%s)", m_buffer.latin1());
433
434 TQStringList list = TQStringList::split ("#", m_buffer.toString());
435 int radix = list[0].toShort();
436 uchar value = list[1].toShort (NULL, radix);
437
438 return value;
439}
440
441uchar AILexer::decode()
442{
443 uchar value = m_temp.toString().toShort(NULL, 8);
444// tqDebug ("got encoded char %c",value);
445 return value;
446}
447
448/* StringBuffer implementation */
449
450int initialSize = 20;
451int addSize = 10;
452
453StringBuffer::StringBuffer () {
454 m_buffer = (char*)calloc (initialSize, sizeof(char));
455 m_length = 0;
456 m_capacity = initialSize;
457}
458
459StringBuffer::~StringBuffer (){
460 free(m_buffer);
461}
462
463void StringBuffer::append (char c){
464 ensureCapacity(m_length + 1);
465 m_buffer[m_length] = c;
466 m_length++;
467}
468
469void StringBuffer::clear(){
470 for (uint i=0; i<m_length; i++) m_buffer[i] = '\0';
471 m_length = 0;
472}
473
474TQString StringBuffer::toString() const {
475 TQString ret(m_buffer);
476 return ret;
477}
478
479void StringBuffer::ensureCapacity (int p_capacity) {
480 if (m_capacity >= p_capacity) return;
481
482 int newSize = m_capacity + addSize;
483 if (p_capacity > newSize) newSize = p_capacity;
484
485 char* oldBuffer = m_buffer;
486 char *newBuffer = (char*)calloc (newSize, sizeof(char));
487 strcpy (newBuffer, m_buffer);
488 free(oldBuffer);
489 m_buffer = newBuffer;
490 m_capacity = newSize;
491}
492
493uint StringBuffer::length() {
494 return m_length;
495}
496
497double StringBuffer::toFloat() {
498 TQString data = toString();
499 return data.toFloat();
500}
501
502int StringBuffer::toInt() {
503 TQString data = toString();
504 return data.toInt();
505}
506
507const char *StringBuffer::latin1() {
508 return m_buffer;
509}
510
511TQString StringBuffer::mid( uint index, uint len) const {
512 TQString data = toString();
513 return data.mid(index,len);
514}