2 * File: sysync_utils.cpp
4 * Author: Lukas Zeller (luz@synthesis.ch)
6 * Provides some helper functions interfacing between SyncML Toolkit
7 * and C++ plus other utilities
9 * Copyright (c) 2001-2009 by Synthesis AG (www.synthesis.ch)
11 * 2001-05-16 : luz : created
15 #ifndef SYSYNC_UTILS_H
16 #define SYSYNC_UTILS_H
18 #include "sysync_globs.h"
19 // include external utils in separate files
20 #include "sysync_b64.h"
21 #include "sysync_md5.h"
22 #include "stringutils.h"
23 #include "lineartime.h"
26 #ifndef FULLY_STANDALONE
31 #include "smldevinfdtd.h"
32 #include "smlmetinfdtd.h"
38 // convert between character sets
39 int charConv(int argc, const char *argv[]);
41 // parse RFC 2822 addr spec
42 int parse2822AddrSpec(int argc, const char *argv[]);
47 // max line size for MIME content (used while encoding and folding)
48 #define MIME_MAXLINESIZE 75
53 chs_unknown, // invalid
54 chs_ascii, // 7 bit ASCII-only, with nearest char conversion for umlauts etc.
59 #ifdef CHINESE_SUPPORT
65 // Note: Char set names are defined after this enum in other files,
66 // such as MimeDirItemType
69 // supported MIME encoding types
76 enc_base64, // b64 including terminating with CRLF at end
77 enc_b, // b64 without termination (as needed in RFC2047)
85 lem_none, // none specified
89 lem_cstr, // as in C strings, '\n' which is 0x0A normally (but might be 0x0D on some platforms)
90 lem_filemaker, // 0x0B (filemaker tab-separated text format, CR is shown as 0x0B within fields
94 extern const char * const lineEndModeNames[numLineEndModes];
97 // literal quoting modes
99 qm_none, // none specified
100 qm_duplsingle, // single quote must be duplicated
101 qm_dupldouble, // double quote must be duplicated
102 qm_backslash, // C-string-style escapes of CR,LF,TAB,BS,\," and ' (but no full c-string escape with \xXX etc.)
106 extern const char * const quotingModeNames[numQuotingModes];
111 The value of this element SHOULD BE one of bin, bool, b64, chr, int,
112 node, null or xml. If the element type is missing, the default value is chr. If the value is
113 bin, then the format of the content is binary data. If the value is bool, then the format of
114 the content is either true or false. If the value is b64, then the format of the content
115 information is binary data that has been character encoded using the Base64 transfer
116 encoding defined by [RFC2045]. If the value is chr, then the format of the content
117 information is clear-text in the character set specified on either the transport protocol, the
118 MIME content type header or the XML prolog. If the value is int, then the format of the
119 content information is numeric text representing an unsigned integer between zero and
120 2**32-1. If the value is node, then the content represents an interior object in the
121 management tree. If the value is null, then there is no content information. This value is
122 used by some synchronization data models to delete the content, but not the presence of
123 the property. If the value is xml, then the format of the content information is XML
124 structured mark-up data.
135 extern const char * const encodingFmtNames[numFmtTypes];
136 extern const char * const encodingFmtSyncMLNames[numFmtTypes];
138 extern const char * const MIMEEncodingNames[numMIMEencodings];
139 extern const char * const MIMECharSetNames[numCharSets];
142 // field (property) data types
144 proptype_chr, // Character
145 proptype_int, // Integer
146 proptype_bool, // Boolean
147 proptype_bin, // Binary
148 proptype_datetime, // Date and time of day
149 proptype_phonenum, // Phone number
150 proptype_text, // plain text
151 proptype_unknown, // unknown
155 extern const char * const propDataTypeNames[numPropDataTypes];
158 // Authorization types
166 extern const char * const authTypeSyncMLNames[numAuthTypes];
167 //extern const char * const authFormatNames[numAuthTypes];
170 // char that is used for non-convertible chars
171 #define INCONVERTIBLE_PLACEHOLDER '_'
174 // encoding functions
176 // encode binary stream and append to string
178 const uInt8 *aBinary,
181 TEncodingTypes aEncoding,
182 sInt16 aMaxLineSize=76,
183 sInt32 aCurrLineSize=0, // how may chars are on the first line
184 bool aSoftBreaksAsCR=false, // if set, soft breaks are not added as CRLF, but only indicated as CR
185 bool aEncodeBinary=false // quoted printable: binary coding: both CR and LF will be
186 // always replaced by "=0D" and "=0A"
189 // decode encoded data and append to string
190 const char *appendDecoded(
194 TEncodingTypes aEncoding
199 // generate RFC2822-style address specificiation
200 // - Common Name will be quoted
201 // - recipient will be put in angle brackets
202 void makeRFC2822AddrSpec(
203 cAppCharP aCommonName,
204 cAppCharP aRecipient,
209 // Parse RFC2822-style address specificiation
210 // - aName will receive name and all (possible) comments
211 // - aRecipient will receive the (first, in case of a group) email address
212 cAppCharP parseRFC2822AddrSpec(
221 // append internal UTF8 string as RFC2047 style encoding
222 const char *appendUTF8AsRFC2047(
227 // parse character string from RFC2047 style encoding to UTF8 internal string
228 const char *appendRFC2047AsUTF8(
229 const char *aRFC2047,
230 stringSize aSize, // max number of chars to look at
232 TLineEndModes aLEM=lem_none
237 // charset conversion functions
239 // generic bintree-based conversion functions
240 typedef uInt16 treeval_t;
245 treeval_t linksstart;
252 #ifdef BINTREE_GENERATOR
254 typedef struct TBinTreeNode {
256 struct TBinTreeNode *nextHigher;
257 struct TBinTreeNode *nextLowerOrEqual;
258 treeval_t value; // valid only if links are both NULL
262 // add a key/value pair to the binary tree
263 void addToBinTree(TBinTreeNode *&aBinTree, treeval_t aMinKey, treeval_t aMaxKey, treeval_t aKey, treeval_t aValue);
265 void disposeBinTree(TBinTreeNode *&aBinTree);
266 // search directly in bintree
267 treeval_t searchBintree(TBinTreeNode *aBinTree, treeval_t aKey, treeval_t aUndefValue, treeval_t aMinKey, treeval_t aMaxKey);
270 // make a flat form representation of the bintree in a one-dimensional array
272 TBinTreeNode *aBinTree, TConvFlatTree &aFlatTree, size_t aArrSize,
273 treeval_t aMinKey, treeval_t aMaxKey, treeval_t aLinksStart, treeval_t aLinksEnd
277 // search flattened bintree for a specific key value
278 treeval_t searchFlatBintree(const TConvFlatTree &aFlatTree, treeval_t aKey, treeval_t aUndefValue);
280 // add byte char as UTF8 to string value and apply charset translation if needed
281 //void appendCharAsUTF8(char c, string &aVal, TCharSets aCharSet);
282 uInt16 appendCharsAsUTF8(const char *aChars, string &aVal, TCharSets aCharSet, uInt16 aNumChars=1);
284 // add string as UTF8 to value and apply charset translation if needed
285 // - if aLineEndChar is specified, occurrence of this will be replaced
286 // by '\n', occurrence of non matching LF/CR will be ignored
287 void appendStringAsUTF8(
288 const char *s, string &aVal,
290 TLineEndModes aLEM=lem_cstr,
291 bool aAllowFilemakerCR=false // if set, 0x0B is interpreted as line end as well
293 // add UTF8 string to value in custom charset
294 // - aLEM specifies line ends to be used
295 // - aQuotingMode specifies what quoting (for ODBC literals for example) should be used
296 // - output is clipped after aMaxBytes bytes (if not 0)
297 // - returns true if all input could be converted, false if output is clipped
298 bool appendUTF8ToString(
299 cAppCharP aUTF8, string &aVal,
301 TLineEndModes aLEM=lem_none,
302 TQuotingModes aQuotingMode=qm_none,
305 // same, but output string is cleared first
306 bool storeUTF8ToString(
307 cAppCharP aUTF8, string &aVal,
309 TLineEndModes aLEM=lem_none,
310 TQuotingModes aQuotingMode=qm_none,
315 // convert UTF8 to UCS4
316 // - returns pointer to next char
317 // - returns UCS4=0 on error (no char, bad sequence, sequence not complete)
318 const char *UTF8toUCS4(const char *aUTF8, uInt32 &aUCS4);
319 // convert UCS4 to UTF8 (0 char is not allowed and will be ignored!)
320 void UCS4toUTF8(uInt32 aUCS4, string &aUTF8);
323 // convert UTF-16 to UCS4
324 // - returns pointer to next char
325 // - returns UCS4=0 on error (no char, bad sequence, sequence not complete)
326 const uInt16 *UTF16toUCS4(const uInt16 *aUTF16P, uInt32 &aUCS4);
327 // convert UCS4 to UTF-16
328 // - returns 0 for UNICODE range UCS4 and first word of UTF-16 for non UNICODE
329 uInt16 UCS4toUTF16(uInt32 aUCS4, uInt16 &aUTF16);
333 // add UTF8 string as UTF-16 byte stream to 8-bit string
334 // - if aLEM is not lem_none, occurrence of any type of Linefeeds
335 // (LF,CR,CRLF and even CRCRLF) in input string will be
336 // replaced by the specified line end type
337 // - output is clipped after ByteString reaches aMaxBytes size (if not 0), = approx half as many Unicode chars
338 // - returns true if all input could be converted, false if output is clipped
339 bool appendUTF8ToUTF16ByteString(
341 string &aUTF16ByteString,
343 TLineEndModes aLEM=lem_none,
347 // add UTF16 byte string as UTF8 to value
348 void appendUTF16AsUTF8(
349 const uInt16 *aUTF16,
350 uInt32 aNumUTF16Chars,
353 bool aConvertLineEnds=false,
354 bool aAllowFilemakerCR=false
358 // MD5 and B64 given string
359 void MD5B64(const char *aString, sInt32 aLen, string &aMD5B64);
361 // format as Timestamp text, usually for logfiles
362 void StringObjTimestamp(string &aStringObj, lineartime_t aTimer);
363 // format as hex byte string
364 void StringObjHexString(string &aStringObj, const uInt8 *aBinary, uInt32 aBinSz);
366 // add CGI to existing URL string
367 bool addCGItoString(string &aStringObj, cAppCharP aCGI, bool noduplicate=true);
370 int countbits(uInt32 aMask);
373 void StringUpper(string &aString);
375 void StringLower(string &aString);
377 // Substitute occurences of pattern with replacement in string
379 string &aString, const char *aPattern, const string &aReplacement,
381 TCharSets aCharSet, TLineEndModes aLEM,
382 TQuotingModes aQuotingMode
385 string &aString, const char *aPattern, const char *aReplacement,
386 sInt32 aPatternLen, sInt32 aReplacementLen,
387 TCharSets aCharSet=chs_unknown, TLineEndModes aLEM=lem_none,
388 TQuotingModes aQuotingMode=qm_none
390 void StringSubst(string &aString, const char *aPattern, const string &aReplacement, sInt32 aPatternLen=-1);
391 void StringSubst(string &aString, const char *aPattern, sInt32 aNumber, sInt32 aPatternLen=-1);
393 i\=0\; *while\(\(i\=([^.]+)\.find\(\"([^"]+)\",i\)\)\!\=string::npos\) *\{ *[^.]+\.replace\(i,([0-9]+),(.+)\)\; i\+\=.*$
394 StringSubst(\1,"\2",\4,\3);
398 // helper macro for allocation of SyncML Toolkit structures from C++ code
399 #define SML_NEW(ty) ((ty*) _smlMalloc(sizeof(ty)))
400 #define SML_FREE(m) smlLibFree(m)
402 // allocate memory via SyncML toolkit allocation function, but throw
403 // exception if it fails. Used by SML
404 void *_smlMalloc(MemSize_t size);
406 // copy PCdata contents into std::string object
407 void smlPCDataToStringObj(const SmlPcdataPtr_t aPcdataP, string &aStringObj);
409 // returns pointer to PCdata contents or null string. If aSizeP!=NULL, length will be stored in *aSize
410 const char *smlPCDataToCharP(const SmlPcdataPtr_t aPcdata, stringSize *aSizeP=NULL);
412 // returns pointer to PCdata contents if existing, NULL otherwise.
413 // If aSizeP!=NULL, length will be stored in *aSize
414 const char *smlPCDataOptToCharP(const SmlPcdataPtr_t aPcdataP, stringSize *aSizeP=NULL);
416 // returns item string or empty string (NEVER NULL)
417 const char *smlItemDataToCharP(const SmlItemPtr_t aItemP);
419 // returns first item string or empty string (NEVER NULL)
420 const char *smlFirstItemDataToCharP(const SmlItemListPtr_t aItemListP);
422 // split Hostname into address and port parts
423 void splitHostname(const char *aHost,string *aAddr,string *aPort);
425 // split URL into protocol, hostname, document name and auth-info (user, password)
426 void splitURL(const char *aURI,string *aProtocol,string *aHost,string *aDoc,string *aUser, string *aPasswd);
428 // returns error code made ready for SyncML sending (that is, remove offset
429 // of 10000 if present, and make generic error 500 for non-SyncML errors,
430 // and return LOCERR_OK as 200)
431 localstatus syncmlError(localstatus aErr);
433 // returns error code made local (that is, offset by 10000 in case aErr is a
434 // SyncML status code <10000, and convert 200 into LOCERR_OK)
435 localstatus localError(localstatus aErr);
437 // returns pure relative URI, if specified relative or absolute to
438 // optionally given server URI
439 const char *relativeURI(const char *aURI,const char *aServerURI=NULL);
441 // returns pointer to source or target LocURI
442 const char *smlSrcTargLocURIToCharP(const SmlTargetPtr_t aSrcTargP);
444 // returns pointer to source or target LocName
445 const char *smlSrcTargLocNameToCharP(const SmlTargetPtr_t aSrcTargP);
447 // returns DevInf pointer if any in specified PCData, NULL otherwise
448 SmlDevInfDevInfPtr_t smlPCDataToDevInfP(const SmlPcdataPtr_t aPCDataP);
450 // returns MetInf pointer if any in specified PCData, NULL otherwise
451 SmlMetInfMetInfPtr_t smlPCDataToMetInfP(const SmlPcdataPtr_t aPCDataP);
453 // returns true on successful conversion of PCData string to format
454 bool smlPCDataToFormat(const SmlPcdataPtr_t aPCDataP, TFmtTypes &aFmt);
457 // returns type from meta
458 const char *smlMetaTypeToCharP(SmlMetInfMetInfPtr_t aMetaP);
460 // returns Next Anchor from meta
461 const char *smlMetaNextAnchorToCharP(SmlMetInfMetInfPtr_t aMetaP);
463 // returns Last Anchor from meta
464 const char *smlMetaLastAnchorToCharP(SmlMetInfMetInfPtr_t aMetaP);
468 SmlPcdataPtr_t newMetaAnchor(const char *aNextAnchor, const char *aLastAnchor=NULL);
471 SmlPcdataPtr_t newMetaType(const char *aMetaType);
474 SmlPcdataPtr_t newMeta(void);
476 // copy meta from existing meta (for data items only
477 // anchor, mem, emi, maxobjsize, nonce are not copied!)
478 SmlPcdataPtr_t copyMeta(SmlPcdataPtr_t aOldMetaP);
481 // add an item to an item list
482 SmlItemListPtr_t *addItemToList(
483 SmlItemPtr_t aItemP, // existing item data structure, ownership is passed to list
484 SmlItemListPtr_t *aItemListPP // adress of pointer to existing item list or NULL
487 // add a CTData item to a CTDataList
488 SmlDevInfCTDataListPtr_t *addCTDataToList(
489 SmlDevInfCTDataPtr_t aCTDataP, // existing CTData item data structure, ownership is passed to list
490 SmlDevInfCTDataListPtr_t *aCTDataListPP // adress of pointer to existing item list or NULL
493 // add a CTDataProp item to a CTDataPropList
494 SmlDevInfCTDataPropListPtr_t *addCTDataPropToList(
495 SmlDevInfCTDataPropPtr_t aCTDataPropP, // existing CTDataProp item data structure, ownership is passed to list
496 SmlDevInfCTDataPropListPtr_t *aCTDataPropListPP // adress of pointer to existing item list or NULL
499 // add a CTData describing a property (as returned by newDevInfCTData())
500 // as a new property without parameters to a CTDataPropList
501 SmlDevInfCTDataPropListPtr_t *addNewPropToList(
502 SmlDevInfCTDataPtr_t aPropCTData, // CTData describing property
503 SmlDevInfCTDataPropListPtr_t *aCTDataPropListPP // adress of pointer to existing item list or NULL
506 // add PCData element to a PCData list
507 SmlPcdataListPtr_t *addPCDataToList(
508 SmlPcdataPtr_t aPCDataP, // Existing PCData element to be added, ownership is passed to list
509 SmlPcdataListPtr_t *aPCDataListPP // adress of pointer to existing PCData list or NULL
512 // add PCData string to a PCData list
513 SmlPcdataListPtr_t *addPCDataStringToList(
514 const char *aString, // String to be added
515 SmlPcdataListPtr_t *aPCDataListPP // adress of pointer to existing PCData list or NULL
518 // create new optional location (source or target)
519 SmlSourcePtr_t newOptLocation(
521 const char *aLocName=NULL
524 // create new location (source or target)
525 SmlSourcePtr_t newLocation(
527 const char *aLocName=NULL
530 // create new empty Item
531 SmlItemPtr_t newItem(void);
533 // create new Item with string-type data
534 SmlItemPtr_t newStringDataItem(
539 // create format PCData
540 SmlPcdataPtr_t newPCDataFormat(
545 // create new string-type PCData, if NULL or empty string is passed for aData,
546 // NULL is returned (optional info not there)
547 SmlPcdataPtr_t newPCDataFormatted(
548 const uInt8 *aData, // data
549 sInt32 aLength, // length of data, if<0 then string length is calculated
550 TFmtTypes aEncType, // encoding
551 bool aNeedsOpaque // set opaque needed (string that could confuse XML parsing or even binary)
554 // create new string-type PCData, if NULL is passed for aString, NULL is returned (optional info not there)
555 SmlPcdataPtr_t newPCDataOptString(
557 sInt32 aLength=-1 // length of string, if<0 then length is calculated
560 // create new string-type PCData, if NULL is passed for aString,
561 // NULL is returned (optional info not there)
562 // if empty string is passed, PCData with empty contents will be created
563 SmlPcdataPtr_t newPCDataOptEmptyString(
565 sInt32 aLength=-1 // length of string, if<0 then length is calculated
568 // create new string-type PCData, if NULL is passed for aString, an empty string is created
569 SmlPcdataPtr_t newPCDataString(
571 sInt32 aLength=-1 // length of string, if<0 then length is calculate
574 // create new PCData, aOpaque can be used to generate non-string data
575 SmlPcdataPtr_t newPCDataStringX(
576 const uInt8 *aString,
577 bool aOpaque=false, // if set, an opaque method (OPAQUE or CDATA) is used
578 sInt32 aLength=-1 // length of string, if<0 then length is calculate
582 // create new string-type PCData from C++ string
583 SmlPcdataPtr_t newPCDataString(const string &aString);
585 // create new decimal string representation of long as PCData
586 SmlPcdataPtr_t newPCDataLong(sInt32 aLong);
588 // returns true on successful conversion of PCData string to long
589 bool smlPCDataToLong(const SmlPcdataPtr_t aPCDataP, sInt32 &aLong);
590 bool smlPCDataToULong(const SmlPcdataPtr_t aPCDataP, uInt32 &aLong);
593 // create challenge of requested type
594 SmlChalPtr_t newChallenge(TAuthTypes aAuthType, const string &aNextNonce, bool aBinaryAllowed);
596 // Nonce generator allowing last-session nonce to be correctly re-generated in next session
597 void generateNonce(string &aNonce, const char *aDevStaticString, sInt32 aSessionStaticID);
599 // create new property or param descriptor for CTCap
600 SmlDevInfCTDataPtr_t newDevInfCTData(cAppCharP aName,uInt32 aSize=0, bool aNoTruncate=false, uInt32 aMaxOccur=0, cAppCharP aDataType=NULL);
602 // frees prototype element and sets calling pointer to NULL
603 void FreeProtoElement(void * &aVoidP);
604 // macro to overcome pointer reference conversion constraints
606 #define FREEPROTOELEMENT(p) FreeProtoElement((void *&)p)
608 template <class T> void FREEPROTOELEMENT(T *&p)
610 smlFreeProtoElement(static_cast<void *>(p));
615 } // namespace sysync