2 * File: DataObjType.cpp
4 * Author: Beat Forster (bfo@synthesis.ch)
7 * base class for data object based items (EMAILOBJ, FILEOBJ, FOLDEROBJ)
8 * implemented for OMA DS V1.2
10 * Copyright (c) 2005-2009 by Synthesis AG (www.synthesis.ch)
12 * 2005-07-20 : bfo : created from TextItemType
17 #include "prefix_file.h"
20 #include "dataobjtype.h"
23 using namespace sysync;
27 const char* BeginCDATA= "<![CDATA[";
28 const char* EndCDATA= "]]>";
29 const char* LowerCDATA= "]]]]>><![CDATA["; // only for the xml representation
30 const char* DoubleCEnd= "]]]]";
35 TTagMapDefinition::TTagMapDefinition(TConfigElement *aParentElementP, sInt16 aFid) :
36 TConfigElement("lm",aParentElementP)
38 fFid= aFid; // save field ID
39 clear(); // init others
40 } // TTagMapDefinition::TTagMapDefinition
44 void TTagMapDefinition::clear(void)
52 #ifdef OBJECT_FILTERING
53 TCFG_CLEAR(fFilterKeyword);
55 } // TTagMapDefinition::clear
59 #ifdef CONFIGURABLE_TYPE_SUPPORT
60 // server config element parsing
61 bool TTagMapDefinition::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
63 // checking the elements
64 if (strucmp(aElementName,"xmltag" )==0) expectString(fXmlTag); // the tag's name
65 else if (strucmp(aElementName,"xmlattr" )==0) expectString(fXmlAttr); // and its (optional) attribute(s)
66 else if (strucmp(aElementName,"booltype" )==0) expectBool (fBoolType); // a boolean field
67 else if (strucmp(aElementName,"embeddeditem" )==0) expectBool (fEmbedded); // an embedded item
68 else if (strucmp(aElementName,"parent" )==0) expectString(fParent); // the parent's tag name
69 #ifdef OBJECT_FILTERING
70 else if (strucmp(aElementName,"filterkeyword")==0) expectString(fFilterKeyword); // the parent's tag name
74 else return TConfigElement::localStartElement(aElementName,aAttributes,aLine);
78 } // TTagMapDefinition::localStartElement
82 TTagMapDefinition::~TTagMapDefinition() {
84 } // TTagMapDefinition::~TTagMapDefinition
88 // -------------------------------------------------------------------------------------------
89 // XML based datatype config
90 TDataObjConfig::TDataObjConfig(const char* aName, TConfigElement *aParentElement) :
91 TMultiFieldTypeConfig(aName,aParentElement)
94 } // TDataObjConfig::TDataObjConfig
97 TDataObjConfig::~TDataObjConfig()
99 // make sure everything is deleted (was missing long time and caused mem leaks!)
101 } // TDataObjConfig::~TDataObjConfig
105 void TDataObjConfig::clear(void)
109 TTagMapList::iterator pos;
110 for (pos= fTagMaps.begin();
111 pos!=fTagMaps.end(); pos++) delete *pos;
116 } // TDataObjConfig::clear
119 // create Sync Item Type of appropriate type from config
120 TSyncItemType *TDataObjConfig::newSyncItemType(TSyncSession *aSessionP, TSyncDataStore *aDatastoreP)
123 SYSYNC_THROW(TSyncException(DEBUGTEXT("TDataObjConfig::newSyncItemType: no fFieldListP","txit1")));
129 fTypeVersion.c_str(),
133 } // TDataObjConfig::newSyncItemType
136 #ifdef CONFIGURABLE_TYPE_SUPPORT
137 // config element parsing
138 bool TDataObjConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
140 // checking the elements
141 if (strucmp(aElementName,"tagmap")==0) {
142 // <tagmap field="SUBJECT">
143 const char* nam = getAttr(aAttributes,"field");
146 return fail("'use' must be specfied before first <tagmap>");
148 // %%% add context here if we have any
149 sInt16 fid = TConfigElement::getFieldIndex(nam,fFieldListP);
150 if (fid==VARIDX_UNDEFINED) return fail("'field' references unknown field '%s'",nam);
153 TTagMapDefinition *tagmapP= new TTagMapDefinition(this,fid);
155 fTagMaps.push_back(tagmapP);
156 // - let element handle parsing
157 expectChildParsing(*tagmapP);
162 if (TMultiFieldTypeConfig::localStartElement(aElementName,aAttributes,aLine)) return true;
164 // let the profile parse as if it was inside a "textprofile"
166 return delegateParsingTo(fProfileConfigP,aElementName,aAttributes,aLine);
168 return false; // cannot parse
169 } // TDataObjConfig::localStartElement
173 void TDataObjConfig::localResolve(bool aLastPass)
177 inherited::localResolve(aLastPass);
178 } // TDataObjConfig::localResolve
182 #ifdef HARDCODED_TYPE_SUPPORT
183 TTagMapDefinition *TDataObjConfig::addTagMap( sInt16 aFid, const char* aXmlTag,
184 bool aBoolType, bool aEmbedded,
185 const char* aParent )
188 TTagMapDefinition *tagmapP = new TTagMapDefinition(this,aFid);
191 TCFG_ASSIGN(tagmapP->fXmlTag,aXmlTag);
192 tagmapP->fBoolType= aBoolType;
193 tagmapP->fEmbedded= aEmbedded;
194 tagmapP->fParent = aParent;
197 fTagMaps.push_back(tagmapP);
200 } // TDataObjConfig::addTagMap
206 * Implementation of TDataObjType
208 TDataObjType::TDataObjType(
209 TSyncSession *aSessionP,
210 TDataTypeConfig *aTypeCfgP, // type config
213 TSyncDataStore *aRelatedDatastoreP,
214 TFieldListConfig *aFieldDefinitions // field definitions
216 TMultiFieldItemType(aSessionP,aTypeCfgP,aCTType,aVerCT,aRelatedDatastoreP,aFieldDefinitions),
217 fProfileHandlerP(NULL)
219 // save typed config pointer again
220 fTypeCfgP = static_cast<TDataObjConfig *>(aTypeCfgP);
221 // create the profile handler
222 fProfileHandlerP = static_cast<TDataObjConfig *>(aTypeCfgP)->fProfileConfigP->newProfileHandler(this);
224 fProfileHandlerP->setProfileMode(fTypeCfgP->fProfileMode);
225 } // TDataObjType::TDataObjType
228 TDataObjType::~TDataObjType()
230 // handler not needed any more
231 if (fProfileHandlerP)
232 delete fProfileHandlerP;
233 } // TDataObjType::~TDataObjType
237 #ifdef OBJECT_FILTERING
238 // get field index of given filter expression identifier.
239 sInt16 TDataObjType::getFilterIdentifierFieldIndex(const char *aIdentifier, uInt16 aIndex)
241 // check if explicit field level identifier
242 if (strucmp(aIdentifier,"F.",2)==0) {
243 // explicit field identifier, skip property lookup
247 // search tagmaps for tagged fields
248 TTagMapList::iterator pos;
249 for (pos= fTypeCfgP->fTagMaps.begin();
250 pos!=fTypeCfgP->fTagMaps.end(); pos++) {
251 // first priority: compare with explicit filterkeyword, if any
252 if (!TCFG_ISEMPTY((*pos)->fFilterKeyword)) {
253 // compare with filterkeyword
254 if (strucmp(TCFG_CSTR((*pos)->fFilterKeyword),aIdentifier)==0)
257 else if (!TCFG_ISEMPTY((*pos)->fXmlTag)) {
258 // compare with xml tag name itself
259 if (strucmp(TCFG_CSTR((*pos)->fXmlTag),aIdentifier)==0)
263 // no matching tag found, let TTextProfileHandler search for its own filter identifiers
264 if (fProfileHandlerP) {
265 sInt16 fid = fProfileHandlerP->getFilterIdentifierFieldIndex(aIdentifier,aIndex);
266 if (fid!=FID_NOT_SUPPORTED)
269 // no tagged field found, search underlying field list
271 // if no field ID found so far, look up in field list
272 return TMultiFieldItemType::getFilterIdentifierFieldIndex(aIdentifier, aIndex);
273 } // TDataObjType::getFilterIdentifierFieldIndex
278 // helper to create same-typed instance via base class
279 TSyncItemType *TDataObjType::newCopyForSameType(
280 TSyncSession *aSessionP, // the session
281 TSyncDataStore *aDatastoreP // the datastore
284 // create new itemtype of appropriate derived class type that can handle
286 MP_RETURN_NEW(TDataObjType,DBG_OBJINST,"TDataObjType",TDataObjType(
294 } // TDataObjType::newCopyForSameType
297 // create new sync item of proper type and optimization for specified target
298 TSyncItem *TDataObjType::internalNewSyncItem(TSyncItemType *aTargetItemTypeP, TLocalEngineDS *aLocalDatastoreP)
300 // All DataObjs are stored in MultiFieldItems
301 if (!aTargetItemTypeP->isBasedOn(ity_multifield))
302 SYSYNC_THROW(TSyncException(DEBUGTEXT("TDataObjType::internalNewSyncItem with bad-typed target","txit3")));
303 TMultiFieldItemType *targetitemtypeP =
304 static_cast<TMultiFieldItemType *> (aTargetItemTypeP);
305 return new TMultiFieldItem(this,targetitemtypeP);
306 } // TDataObjType::internalNewSyncItem
309 // fill in SyncML data (but leaves IDs empty)
310 bool TDataObjType::internalFillInData(
311 TSyncItem *aSyncItemP, // SyncItem to be filled with data
312 SmlItemPtr_t aItemP, // SyncML toolkit item Data to be converted into SyncItem (may be NULL if no data, in case of Delete or Map)
313 TLocalEngineDS *aLocalDatastoreP, // local datastore
314 TStatusCommand &aStatusCmd // status command that might be modified in case of error
318 if (!aSyncItemP->isBasedOn(ity_multifield))
319 SYSYNC_THROW(TSyncException(DEBUGTEXT("TDataObjType::internalFillInData: incompatible item class","txit4")));
320 TMultiFieldItem *itemP = static_cast<TMultiFieldItem *> (aSyncItemP);
321 // process data if any
325 cAppCharP t = smlPCDataToCharP(aItemP->data,&sz);
326 if (!parseData(t,sz,*itemP,aLocalDatastoreP)) {
328 aStatusCmd.setStatusCode(415); // Unsupported media type or format
329 ADDDEBUGITEM(aStatusCmd,"Error parsing Text content");
335 aStatusCmd.setStatusCode(412); // incomplete command
336 ADDDEBUGITEM(aStatusCmd,"No data found in item");
339 // ok, let ancestor process data as well
340 return TMultiFieldItemType::internalFillInData(aSyncItemP,aItemP,aLocalDatastoreP,aStatusCmd);
341 } // TDataObjType::internalFillInData
344 // sets data and meta from SyncItem data, but leaves source & target untouched
345 bool TDataObjType::internalSetItemData(
346 TSyncItem *aSyncItemP, // the syncitem to be represented as SyncML
347 SmlItemPtr_t aItem, // item with NULL meta and NULL data
348 TLocalEngineDS *aLocalDatastoreP // local datastore
352 if (!aSyncItemP->isBasedOn(ity_multifield))
353 SYSYNC_THROW(TSyncException(DEBUGTEXT("TDataObjType::internalSetItemData: incompatible item class","txit4")));
354 TMultiFieldItem *itemP = static_cast<TMultiFieldItem *> (aSyncItemP);
355 // let ancestor prepare first
356 if (!TMultiFieldItemType::internalSetItemData(aSyncItemP,aItem,aLocalDatastoreP)) return false;
357 // generate data item
359 generateData(aLocalDatastoreP,*itemP,dataitem);
360 // put data item into opaque/cdata PCData (note that dataitem could be BINARY string, so we need to pass size!)
361 aItem->data=newPCDataStringX((const uInt8 *)dataitem.c_str(),true,dataitem.size());
364 } // TDataObjType::internalSetItemData
368 static void AddXmlTag( string &aString, string aTag, bool newline= false )
370 aString+= "<" + aTag + ">";
371 if (newline) aString+= "\n";
375 static void AddXmlTagEnd( string &aString, string aTag, bool newline= true )
377 aString+= "</" + aTag + ">";
378 if (newline) aString+= "\n";
382 static void AppendXml( string &aString, string aTag, const char* value, bool tagDone= false )
385 if (!tagDone) AddXmlTag( aString, aTag );
388 AddXmlTagEnd( aString, aTag );
393 static void AppendCDATA( string &aString, const char* aTag, const char* aValue )
395 AddXmlTag( aString, aTag ); // must be shown according to OMA DS 1.2,
396 // even if the body is empty
398 aString+= BeginCDATA; // only for the xml representation
399 aString+= aValue; // the body
400 //%%% luz: not needed here as there is no enclosing CData any more (or this will be done when needed by the SML encoder!)
401 //aString+= LowerCDATA; // only for the xml representation
405 AddXmlTagEnd( aString, aTag );
409 string TDataObjType::getAttr( TMultiFieldItem &aItem, const char* aXmlTag, const char* aXmlAttr )
412 TTagMapList::iterator pos;
415 // search for an element, which matches for both <aXmlTag> and <aXmlAttr>
416 for (pos= fTypeCfgP->fTagMaps.begin();
417 pos!=fTypeCfgP->fTagMaps.end(); pos++) {
418 fieldP= aItem.getField( (*pos)->fFid ); // this is the element we're looking for
419 if (strcmp( aXmlTag, TCFG_CSTR((*pos)->fXmlTag ))==0 &&
420 strcmp( aXmlAttr,TCFG_CSTR((*pos)->fXmlAttr))==0) {
421 fieldP->getAsString( v ); // this is the attribute we're looking for
426 return v; // <v> is "", if no attribute found
427 } // TDataObjType::getAttr
430 // generate Data item (includes header and footer)
431 void TDataObjType::generateData(TLocalEngineDS *aDatastoreP, TMultiFieldItem &aItem, string &aString)
434 PDEBUGPRINTFX(DBG_GEN+DBG_HOT,("Generating:") );
435 aItem.debugShowItem(DBG_GEN);
439 TItemField* fieldDocType; // the reference to the "DOCTYPE" (File/Folder/Email) field
440 TTagMapList::iterator pos;
444 bool tagOpened= false;
446 //%%% luz: do not add extra CData here, this will be done when needed by the SML encoder!
447 //aString= BeginCDATA; // start a CDATA sequence
449 fieldDocType= aItem.getField( "DOCTYPE" );
451 fieldDocType->getAsString( docT ); // main tag, straight forward implementation
452 AddXmlTag ( aString, docT, true );
455 // go thru the tag element list and get the matching element
456 for (pos= fTypeCfgP->fTagMaps.begin();
457 pos!=fTypeCfgP->fTagMaps.end(); pos++) {
458 fieldP= aItem.getField( (*pos)->fFid ); // this is the element we're looking for
459 if (!fieldP || // not a valid field
460 fieldP==fieldDocType) continue; // has been done outside already, ignore it
462 bool isArr= fieldP->isArray();
463 sInt16 maxI= 1; // do it once w/o array
464 if (isArr) maxI= fieldP->arraySize();
465 if (maxI==0) continue; // it is an array w/o any items, skip it
467 if ((*pos)->fEmbedded && fProfileHandlerP) {
468 // set related datastore so handler can access session specific datastore state
469 fProfileHandlerP->setRelatedDatastore(aDatastoreP);
470 fProfileHandlerP->generateText(aItem, v);
471 AppendCDATA( aString, TCFG_CSTR((*pos)->fXmlTag), v.c_str());
472 continue; // it's done now for this element
475 // the standard case (not embedded): cover both cases: array AND no array
477 for (i= 0; i<maxI; i++) {
478 TItemField* fieldAP= fieldP;
479 if (isArr) fieldAP= fieldP->getArrayField( i );
481 if (fieldAP->isAssigned() &&
482 TCFG_ISEMPTY((*pos)->fParent) &&
483 !inParent.empty()) { AddXmlTagEnd( aString,inParent.c_str() ); inParent= ""; }
485 // there is no native bool representation for the field lists
486 // So do it with the help of an additional flag
488 if (fieldAP->isAssigned()) {
489 if (fieldAP->isBasedOn( fty_blob ) &&
490 fieldAP->hasProxy()) {
491 #ifdef STREAMFIELD_SUPPORT
492 string enc= getAttr( aItem, TCFG_CSTR((*pos)->fXmlTag), "enc" );
494 // according OMA DS 1.2, the endcoding attribute "enc" must be
495 // either not present (no encoding), "quoted-printable" or "base64".
496 // The implementation SHOULD NOT use other enc attribute values.
497 const char* ptr = fieldAP->getCStr();
498 size_t size= fieldAP->getStreamSize();
500 if (enc.empty()) { // no encoding
501 v.assign( ptr,size ); // => assign directly
503 else if (strucmp( enc.c_str(),"base64" )==0) {
504 char* bb= b64::encode( (uInt8*)ptr,size );
505 v= bb; // maybe one copy operation can be avoided in future
506 b64::free( bb ); // does never contain '\0' => can be treated as normal string
508 else if (strucmp( enc.c_str(),"quoted-printable")==0) {
509 sysync::appendEncoded( (uInt8*)ptr,size, v, enc_quoted_printable,
510 MIME_MAXLINESIZE,0,true,true );
513 v = "unknown_encoding: \"";
519 else if ((*pos)->fBoolType) { // best fitting for integer and string
520 int ii= fieldAP->getAsInteger();
521 switch ( ii ) { // this is the integer - boolean mapping
522 case -1: v= "false"; break; // a strange value for "false"
523 case 0: v= ""; break; // 0 is the empty value (not assigned at parsing)
524 case 1: v= "true"; break; // the 'normal' value for "true"
527 else fieldAP->getAsString( v );
530 // avoid multiple identical elements (even if it's allowed in OMA DS 1.2)
531 if (!TCFG_ISEMPTY((*pos)->fParent)) {
532 bool ok= inParent.empty(); // either iParent==0 or strings are different
533 if (!ok && strucmp( inParent.c_str(),TCFG_CSTR((*pos)->fParent) )!=0) {
534 AddXmlTagEnd( aString,inParent.c_str() ); // switch off old tag first, if different
538 if (ok) { inParent= (*pos)->fParent;
539 AddXmlTag( aString,inParent.c_str(), true );
545 if (TCFG_ISEMPTY((*pos)->fXmlAttr)) { // w/o attributes
546 if (tagOpened) aString+= ">";
547 AppendXml ( aString, (*pos)->fXmlTag, v.c_str(), tagOpened );
550 else if (!v.empty()) { // with XML attribute handling
553 aString+= TCFG_CSTR((*pos)->fXmlTag);
557 aString+= TCFG_CSTR((*pos)->fXmlAttr);
558 aString+= "=\"" + v + "\"";
564 // Leave the block finally
565 if (!inParent.empty()) AddXmlTagEnd( aString,inParent.c_str());
568 fieldDocType->getAsString( docT ); // end of main tag, straight forward implementation
569 AddXmlTagEnd ( aString, docT );
572 //%%% luz: do not add extra CData here, this will be done when needed by the SML encoder!
573 //aString+= EndCDATA; // terminate the sequence
576 if (PDEBUGTEST(DBG_GEN)) {
577 // note, do not use debugprintf because string is too long
578 PDEBUGPRINTFX(DBG_GEN,("%s", "") );
579 PDEBUGPRINTFX(DBG_GEN,("Successfully generated:") );
580 PDEBUGPUTSX (DBG_GEN+DBG_USERDATA, aString.c_str() );
581 PDEBUGPRINTFX(DBG_GEN+DBG_USERDATA,("%s", "") );
584 } // TDataObjType::generateData
587 /*! Skip white spaces */
588 static void SkipWhiteSP( const char* &p )
590 while (*p==0x0D || // CR
593 *p==' ') p++; // skip leading CR/LF/Tabs and spaces
597 // simple straight forward letter recognition
598 static bool IsLetter( char ch )
601 return ch>='A' && ch<='Z';
605 /*! Get the next tag and value of <p>
607 * @param <aTag> may contain attributes, e.g. <body enc="base64">
608 * @param <direction> +1 go down in the hierarchy
609 * 0 stay on the same level
610 * -1 go up in the hierarchy
612 static bool NextTag( const char* &p, string &aTag, string &aAttr, const char* &aPos, int &aSize,
613 int &level, int &direction )
615 const char* BeginCom= "<!--";
616 const char* EndCom= "-->";
627 q= strstr( p,BeginCom ); // comment ?
631 if (*p!='<') return false; // must start with a tag
633 if (*p=='/') { p++; direction= -1; }
635 q= strstr( p,">" ); if (!q) return false;
636 aTag.assign( p, (unsigned int)( q-p ) ); // this is the tag
638 int pos= aTag.find(" ");
639 if (pos>=0) { // the tag contains some attributes
640 aAttr= aTag.substr( pos+1 ); // ==> get them
641 aTag = aTag.substr( 0,pos ); // the real tag
649 if (direction==-1) return true; // end tag reached
651 if (*p!='<') break; // a value is coming now, not nested
654 q= strstr( p,BeginCom );
656 q= strstr( q, EndCom ); if (!q) return false;
657 p= q + strlen ( EndCom ); continue; // comment is skipped
661 if (q && q==p) break; // an empty value
663 // is it a CDATA section ?
664 q= strstr( p,BeginCDATA );
666 p+= strlen( BeginCDATA );
667 q= strstr( p,DoubleCEnd ); if (!q) return false;
669 aSize= (unsigned int)( q-p );
670 vDone= true; // don't do it later again
672 p= q + strlen( DoubleCEnd );
674 q= strstr( p,BeginCDATA ); if (!q) return false; // nested CDATA skipped
675 p= q + strlen( BeginCDATA );
679 if (!IsLetter( p[ 1 ] )) break; // no nested tag ?
681 level++; direction= 1; // nested tags -> do handling outside
686 q= strstr( p, "</" ); if (!q) return false;
690 aSize= (unsigned int)( q-p );
691 vDone= true; // don't do it later again
695 q= strstr( p, aTag.c_str() ); if (!q || p!=q) return false;
697 q= strstr( p,">" ); if (!q) return false;
704 // the structure for attributes with values
713 VVV() { printf( "hinein\n" ); }
714 ~VVV() { printf( "hinaus '%s'\n", a.c_str() ); }
720 // parse Data item (includes header and footer)
721 bool TDataObjType::parseData(const char *aText, stringSize aSize, TMultiFieldItem &aItem, TLocalEngineDS *aDatastoreP)
724 TTagMapList::iterator pos;
725 string tag, attr, value, docType;
730 typedef std::list<string> TStrList;
731 TStrList tagHierarchy;
732 TStrList::iterator px;
735 typedef std::list<TAField> TAList;
740 if (PDEBUGTEST(DBG_PARSE)) {
741 // very detailed, show item being parsed
742 PDEBUGPRINTFX(DBG_PARSE+DBG_HOT, ("Parsing: ") );
743 PDEBUGPUTSX (DBG_PARSE+DBG_USERDATA, aText);
747 // Go thru all the tags and build temporary stack at <tList>
754 typedef std::list<VVV> VList;
758 vEl.a= "beat"; vv.push_back( vEl );
759 vEl.a= "ee"; vv.push_back( vEl );
760 vEl.a= "luz"; vv.push_back( vEl );
761 vEl.a= "gugus"; vv.push_back( vEl );
765 vx!=vv.end(); vx++) {
766 printf( "soso '%s'\n", (*vx).a.c_str() );
770 const char* p= aText;
771 if (strstr( p, BeginCDATA )==p) p+= strlen( BeginCDATA );
772 while (NextTag( p, tag,attr, vPos,vSize, level,direction )) {
773 // parse all attributes and put them into <aList>
775 while (!attr.empty()) {
776 int apos= attr.find( "=\"" );
777 if (apos<0) { attr= ""; break; }
779 a.name = attr.substr( 0,apos );
780 attr = attr.substr( apos+2 );
782 apos= attr.find( "\"" );
783 if (apos<0) { attr= ""; break; }
785 a.value= attr.substr( 0,apos );
786 attr = attr.substr( apos+1 );
787 while (attr.find(" ")==0) attr= attr.substr( 1 );
789 aList.push_back( a );
793 case -1 : px= tagHierarchy.end(); // are we going up in the hierarchy ?
794 if (px!=tagHierarchy.begin()) // if the list is not empty ...
795 tagHierarchy.erase( --px ); // erase last element
798 case 1 : tagHierarchy.push_back( tag ); // are we going down in the hierarchy ?
802 vPos = docType.c_str();
803 vSize= docType.length();
804 tag = "DOCTYPE"; // assign the document type
805 // go on for this special case
808 // go thru the tag element list and get the matching element
809 for (pos= fTypeCfgP->fTagMaps.begin();
810 pos!=fTypeCfgP->fTagMaps.end(); pos++) {
811 if (strucmp( tag.c_str(),TCFG_CSTR((*pos)->fXmlTag) )==0) {
812 fieldP= aItem.getField( (*pos)->fFid ); // this is the element we're looking for
814 if (fieldP->isAssigned() && // -> allow multiple fields with the same name
815 !fieldP->isArray()) continue; // it is assigned already !
817 // for embedded structures, the content shouldn't be copied
818 // in all other cases, it can still be used as <value> string
819 if (!(*pos)->fEmbedded) value.assign( vPos,vSize ); // this is the value of this tag
821 bool xAtt= !TCFG_ISEMPTY((*pos)->fXmlAttr);
822 if (aList.size()==0) {
823 if (xAtt) continue; // does not fit, both must be either empty
829 for (ax= aList.begin();
830 ax!=aList.end(); ax++) {
831 if (strucmp( (*ax).name.c_str(),TCFG_CSTR((*pos)->fXmlAttr) )==0) {
832 value= (*ax).value.c_str(); break; // for attribute handling take as <value>.
836 if (value.empty()) continue;
841 // there must be either no parent, or the parent must match
842 if ( !TCFG_ISEMPTY((*pos)->fParent) &&
843 strucmp( TCFG_CSTR ((*pos)->fParent),tagHierarchy.back().c_str() )!=0) break;
845 if (fieldP->isBasedOn( fty_blob )) {
846 #ifdef STREAMFIELD_SUPPORT
847 string enc= getAttr( aItem, TCFG_CSTR((*pos)->fXmlTag), "enc" );
852 else if (strucmp( enc.c_str(),"base64" )==0) {
854 uInt8* bb= b64::decode( value.c_str(), 0, &oLen );
855 fieldP->setAsString( (const char*)bb, oLen ); // assign the value
857 break; // already done now (blob assigned correctly
859 else if (strucmp( enc.c_str(),"quoted-printable")==0) {
861 sysync::appendDecoded( value.c_str(),value.length(), v, enc_quoted_printable );
862 fieldP->setAsString( v.c_str(), v.size() ); // assign the value
863 break; // already done now (blob assigned correctly
866 value = "unknown_encoding: \"";
873 // we don't have a boolean type directly, so make a special conversion for it
874 if ((*pos)->fBoolType) { // assuming the field list item is integer for boolean
875 if (strucmp( value.c_str(),"0" )==0) break; // as defined in OMA DS 1.2
876 else if (strucmp( value.c_str(),"false" )==0) value= "-1"; // special boolean treatement
877 else if (strucmp( value.c_str(),"true" )==0) value= "1";
880 // delegate parsing of embedded object
881 if ((*pos)->fEmbedded && fProfileHandlerP) {
882 // set related datastore so handler can access session specific datastore state
883 fProfileHandlerP->setRelatedDatastore(aDatastoreP);
884 // vPos,vSize is not a copy, but a direct reference into <aText>
885 bool ok= fProfileHandlerP->parseText(vPos,vSize, aItem);
888 // aStatusCmd.setStatusCode(415); // Unsupported media type or format
889 // ADDDEBUGITEM(aStatusCmd,"Error parsing Text content");
893 break; // already done (at profile handler)
896 // it's ok now to fill in <value>
897 if (fieldP->isArray()) fieldP->appendString( value.c_str() );
898 else fieldP->setAsString ( value.c_str() ); // assign the value
902 if (aList.size()==0) break;
909 PDEBUGPRINTFX(DBG_PARSE,("Successfully parsed: "));
910 //%%%not again! PDEBUGPUTSX(DBG_PARSE+DBG_USERDATA+DBG_EXOTIC, aText );
911 aItem.debugShowItem(DBG_DATA+DBG_PARSE);
915 } // TDataObjType::parseData
918 // generates SyncML-Devinf property list for type
919 SmlDevInfCTDataPropListPtr_t TDataObjType::newCTDataPropList(TTypeVariantDescriptor aVariantDescriptor)
921 // no properties here
923 } // TDataObjType::newCTDataPropList
926 // Filtering: add keywords and property names to filterCap
927 void TDataObjType::addFilterCapPropsAndKeywords(SmlPcdataListPtr_t &aFilterKeywords, SmlPcdataListPtr_t &aFilterProps, TTypeVariantDescriptor aVariantDescriptor)
929 // add keywords from tagmaps
930 #ifdef OBJECT_FILTERING
931 TTagMapList::iterator pos;
932 for(pos=fTypeCfgP->fTagMaps.begin();pos!=fTypeCfgP->fTagMaps.end();pos++) {
933 // first priority: compare with explicit filterkeyword, if any
934 if (!TCFG_ISEMPTY((*pos)->fFilterKeyword)) {
935 // has a filterkeyword, show it
936 addPCDataStringToList(TCFG_CSTR((*pos)->fFilterKeyword), &aFilterKeywords);
939 // let embedded profile add the keywords
940 if (fProfileHandlerP) {
941 fProfileHandlerP->addFilterCapPropsAndKeywords(aFilterKeywords, aFilterProps, aVariantDescriptor, this);
943 // let base class add own keywords/props
944 inherited::addFilterCapPropsAndKeywords(aFilterKeywords, aFilterProps, aVariantDescriptor);
946 } // TDataObjType::addFilterCapPropsAndKeywords
949 // intended for creating SyncItemTypes for remote databases from
950 // transmitted DevInf.
951 // SyncItemType MUST NOT take ownership of devinf structure passed
952 // (because multiple types might be created from a single CTCap entry)
953 bool TDataObjType::analyzeCTCap(SmlDevInfCTCapPtr_t aCTCapP)
955 // just let parent handle
956 return inherited::analyzeCTCap(aCTCapP);
957 } // TDataObjType::analyzeCTCap
960 /// @brief copy CTCap derived info from another SyncItemType
961 /// @return false if item not compatible
962 /// @note required to create remote type variants from ruleMatch type alternatives
963 bool TDataObjType::copyCTCapInfoFrom(TSyncItemType &aSourceItem)
965 // just let parent handle
966 return inherited::copyCTCapInfoFrom(aSourceItem);
967 } // TDataObjType::copyCTCapInfoFrom
970 } // namespace sysync
972 /* end of TDataObjType implementation */