|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Filename: UCCS_CCommandDecoder.cpp |
|
16 * System Includes |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 |
|
22 #include <stdio.h> |
|
23 #include <string.h> |
|
24 #include <time.h> |
|
25 #include <stdlib.h> |
|
26 #include <iostream.h> |
|
27 #include <assert.h> |
|
28 #include <STDDEF.H> |
|
29 #include <sys/types.h> |
|
30 #include <sys/stat.h> |
|
31 #include <ctype.h> |
|
32 |
|
33 /*********************************************************************************** |
|
34 * |
|
35 * Local Includes |
|
36 * |
|
37 **********************************************************************************/ |
|
38 #include "UCCS_CCommandDecoder.h" |
|
39 |
|
40 |
|
41 /*********************************************************************************** |
|
42 * |
|
43 * Macro Functions |
|
44 * |
|
45 **********************************************************************************/ |
|
46 #define IS_WHITESPACE(c) ((c == '\t')||(c == ' ')||(c == '\n')) |
|
47 #define NOT_IS_WHITESPACE_OR_TERM(c) ((IS_WHITESPACE(c) == 0)&&(c != 0)) |
|
48 #define IS_NAME_CHAR(c) (isdigit(c)||isalpha(c)||(c == '_')) |
|
49 |
|
50 /*********************************************************************************** |
|
51 * |
|
52 * Definitions |
|
53 * |
|
54 **********************************************************************************/ |
|
55 #define TA_FILENAME 1 |
|
56 #define TA_ASSIGNEDVALUE 2 |
|
57 #define TA_INTEGERLITERAL 4 |
|
58 #define TA_STRINGLITERAL 8 |
|
59 |
|
60 //-------------------------------------------------------------------------------------------------- |
|
61 // |
|
62 // Construction |
|
63 // |
|
64 //-------------------------------------------------------------------------------------------------- |
|
65 CCommandDecoder::CCommandDecoder( CDataRecord *aEnvironment ) |
|
66 { |
|
67 iEnvironment = aEnvironment; |
|
68 iLastReply = NULL; |
|
69 } |
|
70 |
|
71 CCommandDecoder::~CCommandDecoder() |
|
72 { |
|
73 } |
|
74 |
|
75 |
|
76 //-------------------------------------------------------------------------------------------------- |
|
77 // |
|
78 // Parse commands here and store as a list of field descriptions |
|
79 // |
|
80 //-------------------------------------------------------------------------------------------------- |
|
81 int CCommandDecoder::ParseCommand( char* aCommandstring, TFieldDesc *aFieldList, int aListLength ) |
|
82 { |
|
83 char *start_name; |
|
84 char *start_value; |
|
85 int element_attributes; |
|
86 char *end_value; |
|
87 int i; |
|
88 int err; |
|
89 |
|
90 // if the command string is null then there is nothing to do |
|
91 if( aCommandstring == NULL ) |
|
92 return UCCS_OK; |
|
93 |
|
94 // process the entire string |
|
95 start_name = aCommandstring; |
|
96 for( i = 0; (i < aListLength) && (*start_name != 0); i++ ) { |
|
97 |
|
98 // init the vars |
|
99 element_attributes = 0; |
|
100 |
|
101 // skip over any whitespace to the next start |
|
102 for( start_name; IS_WHITESPACE(*start_name); start_name++ ) |
|
103 ; |
|
104 |
|
105 // if we are at NULL then exit |
|
106 if( *start_name == 0 ) { |
|
107 continue; |
|
108 } |
|
109 |
|
110 // if the character is not alpha then exit |
|
111 if( isalpha(*start_name) == 0 ) { |
|
112 return UCCS_PARSERFAILEDTOSTOREVALUE; |
|
113 } |
|
114 |
|
115 // otherwise this is the start of the token, look for the '=', only alpha, digit, and '_' |
|
116 // characters are allowed in names |
|
117 for( start_value = start_name; (start_value != NULL) && IS_NAME_CHAR(*start_value); start_value++ ) |
|
118 ; |
|
119 if( start_value == NULL ) { |
|
120 break; |
|
121 } |
|
122 if( *start_value != '=' ) { |
|
123 return UCCS_PARSERFAILEDTOSTOREVALUE; |
|
124 } |
|
125 *start_value = 0; |
|
126 start_value++; |
|
127 |
|
128 // if the character at start_value is alpha then this is an assigned value |
|
129 if( isalpha(*start_value) ) { |
|
130 element_attributes |= TA_ASSIGNEDVALUE; |
|
131 } |
|
132 |
|
133 // if the character at the start is numeric then this is an integer literal |
|
134 if( isdigit(*start_value) ) { |
|
135 element_attributes |= TA_INTEGERLITERAL; |
|
136 } |
|
137 |
|
138 // if the character at the start is '"' then this is a string literal |
|
139 if( *start_value == '"' ) { |
|
140 element_attributes |= TA_STRINGLITERAL; |
|
141 } |
|
142 |
|
143 // if the character is whitespace then this is an error |
|
144 if( IS_WHITESPACE(*start_value) ) { |
|
145 return UCCS_PARSERFAILEDTOSTOREVALUE; |
|
146 } |
|
147 |
|
148 // if the character at start_value is '"' then this is a string literal that may include |
|
149 // whitespace and escaped '\' and '"' characters. At the end of this the start_value should |
|
150 // point to a null terminated string that is what we want |
|
151 if( *start_value == '"' ) { |
|
152 end_value = FindEndOfDoubleQuotes( start_value ); |
|
153 if( end_value == NULL ) { |
|
154 continue; |
|
155 } |
|
156 start_value++; |
|
157 } else { |
|
158 end_value = start_value; |
|
159 for( end_value; NOT_IS_WHITESPACE_OR_TERM(*end_value); end_value++ ) |
|
160 ; |
|
161 } |
|
162 |
|
163 // terminate the value |
|
164 *end_value = 0; |
|
165 |
|
166 // remove the escape sequences - eg. \" to " |
|
167 if(DecodeEscapeSequences(start_value)) { |
|
168 Cleanup( aFieldList, aListLength ); |
|
169 return UCCS_PARSERFAILEDTOSTOREVALUE; |
|
170 } |
|
171 |
|
172 // save the new value |
|
173 err = StoreNextValue( start_name, start_value, element_attributes, aFieldList, i ); |
|
174 if( err != 0 ) { |
|
175 Cleanup( aFieldList, aListLength ); |
|
176 return UCCS_PARSERFAILEDTOSTOREVALUE; |
|
177 } |
|
178 |
|
179 // now move to the next potential token |
|
180 start_name = end_value + 1; |
|
181 } |
|
182 |
|
183 // done |
|
184 return UCCS_OK; |
|
185 } |
|
186 |
|
187 |
|
188 //-------------------------------------------------------------------------------------------------- |
|
189 // |
|
190 // Parse commands here and store as a data record |
|
191 // |
|
192 //-------------------------------------------------------------------------------------------------- |
|
193 int CCommandDecoder::ParseCommandToRecord( char *aCommandstring, CDataRecord *aRecord ) |
|
194 { |
|
195 int err; |
|
196 int i; |
|
197 TFieldDesc iFieldList[MAXFIELDCOUNT]; |
|
198 |
|
199 // Check params |
|
200 assert( aRecord != NULL ); |
|
201 |
|
202 // clear the field descriptions |
|
203 memset( iFieldList, 0, sizeof(TFieldDesc)*MAXFIELDCOUNT ); |
|
204 |
|
205 // Parse the command into buffers |
|
206 err = ParseCommand( aCommandstring, iFieldList, MAXFIELDCOUNT ); |
|
207 if( err != UCCS_OK ) { |
|
208 return err; |
|
209 } |
|
210 |
|
211 // Now add all the fields to the record |
|
212 for( i = 0; (iFieldList[i].iName != NULL) && (i < MAXFIELDCOUNT); i++ ) { |
|
213 if( iFieldList[i].iLength == 0 ) { |
|
214 err = aRecord->NewField( iFieldList[i].iName, iFieldList[i].iValue ); |
|
215 assert( err == UCCS_OK ); |
|
216 } else { |
|
217 err = aRecord->NewField( iFieldList[i].iName, iFieldList[i].iValue, iFieldList[i].iLength ); |
|
218 assert( err == UCCS_OK ); |
|
219 } |
|
220 free( iFieldList[i].iName ); |
|
221 free( iFieldList[i].iValue ); |
|
222 iFieldList[i].iName = 0; |
|
223 iFieldList[i].iValue = 0; |
|
224 iFieldList[i].iLength = 0; |
|
225 } |
|
226 |
|
227 //done |
|
228 return UCCS_OK; |
|
229 } |
|
230 |
|
231 |
|
232 /*********************************************************************************** |
|
233 * |
|
234 * PUBLIC METHOD: SetLastReply - set the last reply to be used in parsing |
|
235 * |
|
236 **********************************************************************************/ |
|
237 void CCommandDecoder::SetLastReply( CDataRecord *aLastReply ) |
|
238 { |
|
239 iLastReply = aLastReply; |
|
240 } |
|
241 |
|
242 |
|
243 //-------------------------------------------------------------------------------------------------- |
|
244 // |
|
245 // PRIVATE METHODS |
|
246 // |
|
247 //-------------------------------------------------------------------------------------------------- |
|
248 |
|
249 //-------------------------------------------------------------------------------------------------- |
|
250 // |
|
251 // Store the value |
|
252 // |
|
253 //-------------------------------------------------------------------------------------------------- |
|
254 int CCommandDecoder::StoreNextValue( char *aName, char *aValue, int aAttributes, TFieldDesc *aFieldList, int aIndex ) |
|
255 { |
|
256 int namelength; |
|
257 int valuelength; |
|
258 // int filesize; |
|
259 int err; |
|
260 int variable_found = 0; |
|
261 char *aAssignedValue; |
|
262 |
|
263 // check params |
|
264 assert( aName != NULL ); |
|
265 assert( aValue != NULL ); |
|
266 assert( aFieldList != NULL ); |
|
267 assert( aFieldList[aIndex].iName == NULL ); |
|
268 assert( aFieldList[aIndex].iValue == NULL ); |
|
269 |
|
270 // store the name |
|
271 _strupr( aName ); |
|
272 namelength = strlen( aName ); |
|
273 (aFieldList[aIndex].iName) = (char*)malloc( namelength + 1 ); |
|
274 assert( (aFieldList[aIndex].iName) != NULL ); |
|
275 strcpy( (aFieldList[aIndex].iName), aName ); |
|
276 |
|
277 // if the assigned values attribute is set then we: value = environment[value'] -- value = lastreply[value'] |
|
278 if( aAttributes & TA_ASSIGNEDVALUE ) { |
|
279 |
|
280 // change the variable name to upper case to remove all case sensitivity |
|
281 _strupr( aValue ); |
|
282 |
|
283 // look in the environment first |
|
284 if( iEnvironment != NULL ) { |
|
285 err = iEnvironment->GetFieldAsString( aValue, &aAssignedValue ); |
|
286 if( err == UCCS_OK ) { |
|
287 aValue = aAssignedValue; |
|
288 variable_found = 1; |
|
289 } |
|
290 } |
|
291 |
|
292 // look in the last reply |
|
293 if( (iLastReply != NULL) && (variable_found == 0) ) { |
|
294 err = iLastReply->GetFieldAsString( aValue, &aAssignedValue ); |
|
295 if( err == UCCS_OK ) { |
|
296 aValue = aAssignedValue; |
|
297 variable_found = 1; |
|
298 } |
|
299 } |
|
300 |
|
301 // if variable wasn't found then return error |
|
302 if( variable_found == 0 ) { |
|
303 return -1; |
|
304 } |
|
305 } |
|
306 |
|
307 // store non-file values |
|
308 if( (aAttributes & TA_FILENAME) == 0 ) { |
|
309 valuelength = strlen( aValue ); |
|
310 (aFieldList[aIndex].iValue) = (char*)malloc( valuelength + 1 ); |
|
311 assert( (aFieldList[aIndex].iValue) != NULL ); |
|
312 strcpy( (aFieldList[aIndex].iValue), aValue ); |
|
313 } |
|
314 |
|
315 // store file value |
|
316 #ifdef OLDSTYLE |
|
317 if( aAttributes & TA_FILENAME ) { |
|
318 |
|
319 // get the size of the file |
|
320 filesize = GetFileSize( aValue ); |
|
321 if( filesize == -1 ) { |
|
322 free( (aFieldList[aIndex].iName) ); |
|
323 (aFieldList[aIndex].iName) = NULL; |
|
324 return -1; |
|
325 } |
|
326 |
|
327 // allocate the memory to hold the file |
|
328 (aFieldList[aIndex].iValue) = (char*)malloc( filesize ); |
|
329 assert( (aFieldList[aIndex].iValue) != NULL ); |
|
330 |
|
331 // set the size |
|
332 aFieldList[aIndex].iLength = filesize; |
|
333 |
|
334 // read the file into memory |
|
335 err = ReadFileIntoBuffer( aValue, (aFieldList[aIndex].iValue), filesize ); |
|
336 if( err != 0 ) { |
|
337 free( (aFieldList[aIndex].iName) ); |
|
338 (aFieldList[aIndex].iName) = NULL; |
|
339 free( (aFieldList[aIndex].iValue) ); |
|
340 (aFieldList[aIndex].iValue) = NULL; |
|
341 return -1; |
|
342 } |
|
343 } |
|
344 #endif |
|
345 |
|
346 // done |
|
347 return 0; |
|
348 } |
|
349 |
|
350 |
|
351 //-------------------------------------------------------------------------------------------------- |
|
352 // |
|
353 // FindEndOfDoubleQuotes -- given a string starting with '"' it returns a pointer to the character |
|
354 // matching '"'. It deals with escaped chars. |
|
355 // |
|
356 //-------------------------------------------------------------------------------------------------- |
|
357 char *CCommandDecoder::FindEndOfDoubleQuotes( char *aString ) |
|
358 { |
|
359 char *str; |
|
360 |
|
361 // the first char MUST be '"' |
|
362 if( aString[0] != '"' ) { |
|
363 return NULL; |
|
364 } |
|
365 |
|
366 // now look for a non-escaped '"' |
|
367 str = aString + 1; |
|
368 while( 1 ) { |
|
369 str = strchr( str, '"' ); |
|
370 if( str == NULL ) { |
|
371 return NULL; |
|
372 } |
|
373 if( str[-1] != '\\' ) { |
|
374 return str; |
|
375 } |
|
376 str++; |
|
377 } |
|
378 |
|
379 // done |
|
380 assert( !"INVALID CODE PATH" ); |
|
381 return NULL; |
|
382 } |
|
383 //-------------------------------------------------------------------------------------------------- |
|
384 |
|
385 |
|
386 //-------------------------------------------------------------------------------------------------- |
|
387 // |
|
388 // GetFileSize -- return the size of a file |
|
389 // |
|
390 //-------------------------------------------------------------------------------------------------- |
|
391 int CCommandDecoder::GetFileSize( char *aFilename ) |
|
392 { |
|
393 struct _stat sinfo; |
|
394 int err; |
|
395 err = _stat( aFilename, &sinfo ); |
|
396 if( err != 0 ) { |
|
397 return -1; |
|
398 } |
|
399 return sinfo.st_size; |
|
400 } |
|
401 |
|
402 |
|
403 //-------------------------------------------------------------------------------------------------- |
|
404 // |
|
405 // GetFileSize -- return the size of a file |
|
406 // |
|
407 //-------------------------------------------------------------------------------------------------- |
|
408 int CCommandDecoder::ReadFileIntoBuffer( char *aFilename, char *aBuff, int aBuffSize ) |
|
409 { |
|
410 FILE *fp; |
|
411 int err; |
|
412 int i; |
|
413 |
|
414 // open the file |
|
415 fp = fopen( aFilename, "rb" ); |
|
416 if( fp == NULL ) { |
|
417 return -1; |
|
418 } |
|
419 |
|
420 // read in the bytes |
|
421 for( i = 0; i < aBuffSize; i++ ) { |
|
422 err = fread( &(aBuff[i]), 1, 1, fp ); |
|
423 if( err != 1 ) { |
|
424 fclose( fp ); |
|
425 return -1; |
|
426 } |
|
427 } |
|
428 |
|
429 // done |
|
430 fclose( fp ); |
|
431 return 0; |
|
432 } |
|
433 |
|
434 |
|
435 //-------------------------------------------------------------------------------------------------- |
|
436 // |
|
437 // Cleanup |
|
438 // |
|
439 //-------------------------------------------------------------------------------------------------- |
|
440 void CCommandDecoder::Cleanup( TFieldDesc *aFieldList, int aLen ) |
|
441 { |
|
442 int i; |
|
443 for( i = 0; i < aLen; i++ ) { |
|
444 if( (aFieldList[i].iName) != NULL ) { |
|
445 free( (aFieldList[i].iName) ); |
|
446 (aFieldList[i].iName) = NULL; |
|
447 } |
|
448 if( (aFieldList[i].iValue) != NULL ) { |
|
449 free( (aFieldList[i].iName) ); |
|
450 (aFieldList[i].iName) = NULL; |
|
451 } |
|
452 } |
|
453 } |
|
454 |
|
455 |
|
456 //-------------------------------------------------------------------------------------------------- |
|
457 // |
|
458 // DecodeEscapeSequences - change \" to " and \\ to \ |
|
459 // |
|
460 //-------------------------------------------------------------------------------------------------- |
|
461 // decode escape sequence |
|
462 // - deliberately chose not to use sscanf's parser; more complicated, performance overhead, & requirement for a seperate string |
|
463 int CCommandDecoder::DecodeEscapeSequences(char *start_value) |
|
464 { |
|
465 int result = 0, read_pos = 0, write_pos = 0; |
|
466 |
|
467 // remove the escape char |
|
468 while (start_value[read_pos] != 0) |
|
469 { |
|
470 if (start_value[read_pos++] == '\\') |
|
471 { |
|
472 char decodedChar = 0; |
|
473 switch (start_value[read_pos++]) |
|
474 { |
|
475 case 'a': decodedChar = '\a'; break; |
|
476 case 'b': decodedChar = '\b'; break; |
|
477 case 'f': decodedChar = '\f'; break; |
|
478 case 'n': decodedChar = '\n'; break; |
|
479 case 'r': decodedChar = '\r'; break; |
|
480 case 't': decodedChar = '\t'; break; |
|
481 case 'v': decodedChar = '\v'; break; |
|
482 case '\\': decodedChar = '\\'; break; |
|
483 case '?': decodedChar = '\?'; break; |
|
484 case '\'': decodedChar = '\''; break; |
|
485 case '\"': decodedChar = '\"'; break; |
|
486 // case '\x"': decodedChar = '\"'; break; - not supported, since this could overrun the char array |
|
487 // case '\o"': decodedChar = '\"'; break; - not supported, functionality not needed |
|
488 default: |
|
489 // unknown |
|
490 result = -1; |
|
491 return result; |
|
492 } |
|
493 start_value[write_pos++] = decodedChar; |
|
494 } |
|
495 else |
|
496 start_value[write_pos++] = start_value[read_pos - 1]; |
|
497 } |
|
498 |
|
499 // re-insert the null char |
|
500 start_value[write_pos] = 0; |
|
501 |
|
502 return result; |
|
503 } |