/* ### * IP: GHIDRA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "slghpattern.hh" uintm DisjointPattern::getMask(int4 startbit,int4 size,bool context) const { PatternBlock *block = getBlock(context); if (block != (PatternBlock *)0) return block->getMask(startbit,size); return 0; } uintm DisjointPattern::getValue(int4 startbit,int4 size,bool context) const { PatternBlock *block = getBlock(context); if (block != (PatternBlock *)0) return block->getValue(startbit,size); return 0; } int4 DisjointPattern::getLength(bool context) const { PatternBlock *block = getBlock(context); if (block != (PatternBlock *)0) return block->getLength(); return 0; } bool DisjointPattern::specializes(const DisjointPattern *op2) const { // Return true, if everywhere this's mask is non-zero // op2's mask is non-zero and op2's value match this's PatternBlock *a,*b; a = getBlock(false); b = op2->getBlock(false); if ((b != (PatternBlock *)0)&&(!b->alwaysTrue())) { // a must match existing block if (a == (PatternBlock *)0) return false; if (!a->specializes(b)) return false; } a = getBlock(true); b = op2->getBlock(true); if ((b != (PatternBlock *)0)&&(!b->alwaysTrue())) { // a must match existing block if (a == (PatternBlock *)0) return false; if (!a->specializes(b)) return false; } return true; } bool DisjointPattern::identical(const DisjointPattern *op2) const { // Return true if patterns match exactly PatternBlock *a,*b; a = getBlock(false); b = op2->getBlock(false); if (b != (PatternBlock *)0) { // a must match existing block if (a == (PatternBlock *)0) { if (!b->alwaysTrue()) return false; } else if (!a->identical(b)) return false; } else { if ((a != (PatternBlock *)0)&&(!a->alwaysTrue())) return false; } a = getBlock(true); b = op2->getBlock(true); if (b != (PatternBlock *)0) { // a must match existing block if (a == (PatternBlock *)0) { if (!b->alwaysTrue()) return false; } else if (!a->identical(b)) return false; } else { if ((a != (PatternBlock *)0)&&(!a->alwaysTrue())) return false; } return true; } static bool resolveIntersectBlock(PatternBlock *bl1,PatternBlock *bl2,PatternBlock *thisblock) { PatternBlock *inter; bool allocated = false; bool res = true; if (bl1 == (PatternBlock *)0) inter = bl2; else if (bl2 == (PatternBlock *)0) inter = bl1; else { allocated = true; inter = bl1->intersect(bl2); } if (inter == (PatternBlock *)0) { if (thisblock != (PatternBlock *)0) res = false; } else if (thisblock == (PatternBlock *)0) res = false; else res = thisblock->identical(inter); if (allocated) delete inter; return res; } bool DisjointPattern::resolvesIntersect(const DisjointPattern *op1,const DisjointPattern *op2) const { // Is this pattern equal to the intersection of -op1- and -op2- if (!resolveIntersectBlock(op1->getBlock(false),op2->getBlock(false),getBlock(false))) return false; return resolveIntersectBlock(op1->getBlock(true),op2->getBlock(true),getBlock(true)); } DisjointPattern *DisjointPattern::restoreDisjoint(const Element *el) { // DisjointPattern factory DisjointPattern *res; if (el->getName() == "instruct_pat") res = new InstructionPattern(); else if (el->getName() == "context_pat") res = new ContextPattern(); else res = new CombinePattern(); res->restoreXml(el); return res; } void PatternBlock::normalize(void) { if (nonzerosize<=0) { // Check if alwaystrue or alwaysfalse offset = 0; // in which case we don't need mask and value maskvec.clear(); valvec.clear(); return; } vector::iterator iter1,iter2; iter1 = maskvec.begin(); // Cut zeros from beginning of mask iter2 = valvec.begin(); while((iter1 != maskvec.end())&&((*iter1)==0)) { iter1++; iter2++; offset += sizeof(uintm); } maskvec.erase(maskvec.begin(),iter1); valvec.erase(valvec.begin(),iter2); if (!maskvec.empty()) { int4 suboff = 0; // Cut off unaligned zeros from beginning of mask uintm tmp = maskvec[0]; while(tmp != 0) { suboff += 1; tmp >>= 8; } suboff = sizeof(uintm)-suboff; if (suboff != 0) { offset += suboff; // Slide up maskvec by suboff bytes for(int4 i=0;i> ((sizeof(uintm)-suboff)*8)); maskvec[i] = tmp; } maskvec.back() <<= suboff*8; for(int4 i=0;i> ((sizeof(uintm)-suboff)*8)); valvec[i] = tmp; } valvec.back() <<= suboff*8; } iter1 = maskvec.end(); // Cut zeros from end of mask iter2 = valvec.end(); while(iter1 != maskvec.begin()) { --iter1; --iter2; if ((*iter1) != 0) break; // Find last non-zero } if (iter1 != maskvec.end()) { iter1++; // Find first zero, in last zero chain iter2++; } maskvec.erase(iter1,maskvec.end()); valvec.erase(iter2,valvec.end()); } if (maskvec.empty()) { offset = 0; nonzerosize = 0; // Always true return; } nonzerosize = maskvec.size() * sizeof(uintm); uintm tmp = maskvec.back(); // tmp must be nonzero while( (tmp&0xff) == 0) { nonzerosize -= 1; tmp >>= 8; } } PatternBlock::PatternBlock(int4 off,uintm msk,uintm val) { // Define mask and value pattern, confined to one uintm offset = off; maskvec.push_back(msk); valvec.push_back(val); nonzerosize = sizeof(uintm); // Assume all non-zero bytes before normalization normalize(); } PatternBlock::PatternBlock(bool tf) { offset = 0; if (tf) nonzerosize = 0; else nonzerosize = -1; } PatternBlock::PatternBlock(const PatternBlock *a,const PatternBlock *b) { // Construct PatternBlock by ANDing two others together PatternBlock *res = a->intersect(b); offset = res->offset; nonzerosize = res->nonzerosize; maskvec = res->maskvec; valvec = res->valvec; delete res; } PatternBlock::PatternBlock(vector &list) { // AND several blocks together to construct new block PatternBlock *res,*next; if (list.empty()) { // If not ANDing anything offset = 0; // make constructed block always true nonzerosize = 0; return; } res = list[0]; for(int4 i=1;iintersect(list[i]); delete res; res = next; } offset = res->offset; nonzerosize = res->nonzerosize; maskvec = res->maskvec; valvec = res->valvec; delete res; } PatternBlock *PatternBlock::clone(void) const { PatternBlock *res = new PatternBlock(true); res->offset = offset; res->nonzerosize = nonzerosize; res->maskvec = maskvec; res->valvec = valvec; return res; } PatternBlock *PatternBlock::commonSubPattern(const PatternBlock *b) const { // The resulting pattern has a 1-bit in the mask // only if the two pieces have a 1-bit and the // values agree PatternBlock *res = new PatternBlock(true); int4 maxlength = (getLength() > b->getLength()) ? getLength() : b->getLength(); res->offset = 0; int4 offset = 0; uintm mask1,val1,mask2,val2; uintm resmask,resval; while(offset < maxlength) { mask1 = getMask(offset*8,sizeof(uintm)*8); val1 = getValue(offset*8,sizeof(uintm)*8); mask2 = b->getMask(offset*8,sizeof(uintm)*8); val2 = b->getValue(offset*8,sizeof(uintm)*8); resmask = mask1 & mask2 & ~(val1^val2); resval = val1 & val2 & resmask; res->maskvec.push_back(resmask); res->valvec.push_back(resval); offset += sizeof(uintm); } res->nonzerosize = maxlength; res->normalize(); return res; } PatternBlock *PatternBlock::intersect(const PatternBlock *b) const { // Construct the intersecting pattern if (alwaysFalse() || b->alwaysFalse()) return new PatternBlock(false); PatternBlock *res = new PatternBlock(true); int4 maxlength = (getLength() > b->getLength()) ? getLength() : b->getLength(); res->offset = 0; int4 offset = 0; uintm mask1,val1,mask2,val2,commonmask; uintm resmask,resval; while(offset < maxlength) { mask1 = getMask(offset*8,sizeof(uintm)*8); val1 = getValue(offset*8,sizeof(uintm)*8); mask2 = b->getMask(offset*8,sizeof(uintm)*8); val2 = b->getValue(offset*8,sizeof(uintm)*8); commonmask = mask1 & mask2; // Bits in mask shared by both patterns if ((commonmask & val1) != (commonmask & val2)) { res->nonzerosize = -1; // Impossible pattern res->normalize(); return res; } resmask = mask1 | mask2; resval = (mask1 & val1) | (mask2 & val2); res->maskvec.push_back(resmask); res->valvec.push_back(resval); offset += sizeof(uintm); } res->nonzerosize = maxlength; res->normalize(); return res; } bool PatternBlock::specializes(const PatternBlock *op2) const { // does every masked bit in -this- match the corresponding // masked bit in -op2- int4 length = 8*op2->getLength(); int4 tmplength; uintm mask1,mask2,value1,value2; int4 sbit = 0; while(sbit < length) { tmplength = length-sbit; if (tmplength > 8*sizeof(uintm)) tmplength = 8*sizeof(uintm); mask1 = getMask(sbit,tmplength); value1 = getValue(sbit,tmplength); mask2 = op2->getMask(sbit,tmplength); value2 = op2->getValue(sbit,tmplength); if ((mask1 & mask2) != mask2) return false; if ((value1 & mask2) != (value2 & mask2)) return false; sbit += tmplength; } return true; } bool PatternBlock::identical(const PatternBlock *op2) const { // Do the mask and value match exactly int4 tmplength; int4 length = 8*op2->getLength(); tmplength = 8*getLength(); if (tmplength > length) length = tmplength; // Maximum of two lengths uintm mask1,mask2,value1,value2; int4 sbit = 0; while(sbit < length) { tmplength = length-sbit; if (tmplength > 8*sizeof(uintm)) tmplength = 8*sizeof(uintm); mask1 = getMask(sbit,tmplength); value1 = getValue(sbit,tmplength); mask2 = op2->getMask(sbit,tmplength); value2 = op2->getValue(sbit,tmplength); if (mask1 != mask2) return false; if ((mask1&value1) != (mask2&value2)) return false; sbit += tmplength; } return true; } uintm PatternBlock::getMask(int4 startbit,int4 size) const { startbit -= 8*offset; // Note the division and remainder here is unsigned. Then it is recast to signed. // If startbit is negative, then wordnum1 is either negative or very big, // if (unsigned size is same as sizeof int) // In either case, shift should come out between 0 and 8*sizeof(uintm)-1 int4 wordnum1 = startbit/(8*sizeof(uintm)); int4 shift = startbit % (8*sizeof(uintm)); int4 wordnum2 = (startbit+size-1)/(8*sizeof(uintm)); uintm res; if ((wordnum1<0)||(wordnum1>=maskvec.size())) res = 0; else res = maskvec[wordnum1]; res <<= shift; if (wordnum1 != wordnum2) { uintm tmp; if ((wordnum2<0)||(wordnum2>=maskvec.size())) tmp = 0; else tmp = maskvec[wordnum2]; res |= (tmp>>(8*sizeof(uintm)-shift)); } res >>= (8*sizeof(uintm) - size); return res; } uintm PatternBlock::getValue(int4 startbit,int4 size) const { startbit -= 8*offset; int4 wordnum1 = startbit/(8*sizeof(uintm)); int4 shift = startbit % (8*sizeof(uintm)); int4 wordnum2 = (startbit+size-1)/(8*sizeof(uintm)); uintm res; if ((wordnum1<0)||(wordnum1>=valvec.size())) res = 0; else res = valvec[wordnum1]; res <<= shift; if (wordnum1 != wordnum2) { uintm tmp; if ((wordnum2<0)||(wordnum2>=valvec.size())) tmp = 0; else tmp = valvec[wordnum2]; res |= (tmp>>(8*sizeof(uintm)-shift)); } res >>= (8*sizeof(uintm) - size); return res; } bool PatternBlock::isInstructionMatch(ParserWalker &walker) const { if (nonzerosize<=0) return (nonzerosize==0); int4 off = offset; for(int4 i=0;i\n"; for(int4 i=0;i\n"; } s << "\n"; } void PatternBlock::restoreXml(const Element *el) { { istringstream s(el->getAttributeValue("offset")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> offset; } { istringstream s(el->getAttributeValue("nonzero")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> nonzerosize; } const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); uintm mask,val; while(iter != list.end()) { Element *subel = *iter; { istringstream s(subel->getAttributeValue("mask")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> mask; } { istringstream s(subel->getAttributeValue("val")); s.unsetf(ios::dec | ios::hex | ios::oct); s >> val; } maskvec.push_back(mask); valvec.push_back(val); ++iter; } normalize(); } Pattern *InstructionPattern::doAnd(const Pattern *b,int4 sa) const { if (b->numDisjoint()>0) return b->doAnd(this,-sa); const CombinePattern *b2 = dynamic_cast(b); if (b2 != (const CombinePattern *)0) return b->doAnd(this,-sa); const ContextPattern *b3 = dynamic_cast(b); if (b3 != (const ContextPattern *)0) { InstructionPattern *newpat = (InstructionPattern *)simplifyClone(); if (sa < 0) newpat->shiftInstruction(-sa); return new CombinePattern((ContextPattern *)b3->simplifyClone(),newpat); } const InstructionPattern *b4 = (const InstructionPattern *)b; PatternBlock *respattern; if (sa < 0) { PatternBlock *a = maskvalue->clone(); a->shift(-sa); respattern = a->intersect(b4->maskvalue); delete a; } else { PatternBlock *c = b4->maskvalue->clone(); c->shift(sa); respattern = maskvalue->intersect(c); delete c; } return new InstructionPattern(respattern); } Pattern *InstructionPattern::commonSubPattern(const Pattern *b,int4 sa) const { if (b->numDisjoint()>0) return b->commonSubPattern(this,-sa); const CombinePattern *b2 = dynamic_cast(b); if (b2 != (const CombinePattern *)0) return b->commonSubPattern(this,-sa); const ContextPattern *b3 = dynamic_cast(b); if (b3 != (const ContextPattern *)0) { InstructionPattern *res = new InstructionPattern(true); return res; } const InstructionPattern *b4 = (const InstructionPattern *)b; PatternBlock *respattern; if (sa < 0) { PatternBlock *a = maskvalue->clone(); a->shift(-sa); respattern = a->commonSubPattern(b4->maskvalue); delete a; } else { PatternBlock *c = b4->maskvalue->clone(); c->shift(sa); respattern = maskvalue->commonSubPattern(c); delete c; } return new InstructionPattern(respattern); } Pattern *InstructionPattern::doOr(const Pattern *b,int4 sa) const { if (b->numDisjoint()>0) return b->doOr(this,-sa); const CombinePattern *b2 = dynamic_cast(b); if (b2 != (const CombinePattern *)0) return b->doOr(this,-sa); DisjointPattern *res1,*res2; res1 = (DisjointPattern *)simplifyClone(); res2 = (DisjointPattern *)b->simplifyClone(); if (sa < 0) res1->shiftInstruction(-sa); else res2->shiftInstruction(sa); return new OrPattern(res1,res2); } void InstructionPattern::saveXml(ostream &s) const { s << "\n"; maskvalue->saveXml(s); s << "\n"; } void InstructionPattern::restoreXml(const Element *el) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); maskvalue = new PatternBlock(true); maskvalue->restoreXml(*iter); } Pattern *ContextPattern::doOr(const Pattern *b,int4 sa) const { const ContextPattern *b2 = dynamic_cast(b); if (b2 == (const ContextPattern *)0) return b->doOr(this,-sa); return new OrPattern((DisjointPattern *)simplifyClone(),(DisjointPattern *)b2->simplifyClone()); } Pattern *ContextPattern::doAnd(const Pattern *b,int4 sa) const { const ContextPattern *b2 = dynamic_cast(b); if (b2 == (const ContextPattern *)0) return b->doAnd(this,-sa); PatternBlock *resblock = maskvalue->intersect(b2->maskvalue); return new ContextPattern(resblock); } Pattern *ContextPattern::commonSubPattern(const Pattern *b,int4 sa) const { const ContextPattern *b2 = dynamic_cast(b); if (b2 == (const ContextPattern *)0) return b->commonSubPattern(this,-sa); PatternBlock *resblock = maskvalue->commonSubPattern(b2->maskvalue); return new ContextPattern(resblock); } void ContextPattern::saveXml(ostream &s) const { s << "\n"; maskvalue->saveXml(s); s << "\n"; } void ContextPattern::restoreXml(const Element *el) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); maskvalue = new PatternBlock(true); maskvalue->restoreXml(*iter); } CombinePattern::~CombinePattern(void) { if (context != (ContextPattern *)0) delete context; if (instr != (InstructionPattern *)0) delete instr; } bool CombinePattern::isMatch(ParserWalker &walker) const { if (!instr->isMatch(walker)) return false; if (!context->isMatch(walker)) return false; return true; } bool CombinePattern::alwaysTrue(void) const { return (context->alwaysTrue() && instr->alwaysTrue()); } bool CombinePattern::alwaysFalse(void) const { return (context->alwaysFalse() || instr->alwaysFalse()); } Pattern *CombinePattern::doAnd(const Pattern *b,int4 sa) const { CombinePattern *tmp; if (b->numDisjoint() != 0) return b->doAnd(this,-sa); const CombinePattern *b2 = dynamic_cast(b); if (b2 != (CombinePattern *)0) { ContextPattern *c = (ContextPattern *)context->doAnd(b2->context,0); InstructionPattern *i = (InstructionPattern *)instr->doAnd(b2->instr,sa); tmp = new CombinePattern(c,i); } else { const InstructionPattern *b3 = dynamic_cast(b); if (b3 != (const InstructionPattern *)0) { InstructionPattern *i = (InstructionPattern *)instr->doAnd(b3,sa); tmp = new CombinePattern((ContextPattern *)context->simplifyClone(),i); } else { // Must be a ContextPattern ContextPattern *c = (ContextPattern *)context->doAnd(b,0); InstructionPattern *newpat = (InstructionPattern *) instr->simplifyClone(); if (sa < 0) newpat->shiftInstruction(-sa); tmp = new CombinePattern(c,newpat); } } return tmp; } Pattern *CombinePattern::commonSubPattern(const Pattern *b,int4 sa) const { Pattern *tmp; if (b->numDisjoint() != 0) return b->commonSubPattern(this,-sa); const CombinePattern *b2 = dynamic_cast(b); if (b2 != (CombinePattern *)0) { ContextPattern *c = (ContextPattern *)context->commonSubPattern(b2->context,0); InstructionPattern *i = (InstructionPattern *)instr->commonSubPattern(b2->instr,sa); tmp = new CombinePattern(c,i); } else { const InstructionPattern *b3 = dynamic_cast(b); if (b3 != (const InstructionPattern *)0) tmp = instr->commonSubPattern(b3,sa); else // Must be a ContextPattern tmp = context->commonSubPattern(b,0); } return tmp; } Pattern *CombinePattern::doOr(const Pattern *b,int4 sa) const { if (b->numDisjoint() != 0) return b->doOr(this,-sa); DisjointPattern *res1 = (DisjointPattern *)simplifyClone(); DisjointPattern *res2 = (DisjointPattern *)b->simplifyClone(); if (sa < 0) res1->shiftInstruction(-sa); else res2->shiftInstruction(sa); OrPattern *tmp = new OrPattern(res1,res2); return tmp; } Pattern *CombinePattern::simplifyClone(void) const { // We should only have to think at "our" level if (context->alwaysTrue()) return instr->simplifyClone(); if (instr->alwaysTrue()) return context->simplifyClone(); if (context->alwaysFalse()||instr->alwaysFalse()) return new InstructionPattern(false); return new CombinePattern((ContextPattern *)context->simplifyClone(), (InstructionPattern *)instr->simplifyClone()); } void CombinePattern::saveXml(ostream &s) const { s << "\n"; context->saveXml(s); instr->saveXml(s); s << "\n"; } void CombinePattern::restoreXml(const Element *el) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); context = new ContextPattern(); context->restoreXml(*iter); ++iter; instr = new InstructionPattern(); instr->restoreXml(*iter); } OrPattern::OrPattern(DisjointPattern *a,DisjointPattern *b) { orlist.push_back(a); orlist.push_back(b); } OrPattern::OrPattern(const vector &list) { vector::const_iterator iter; for(iter=list.begin();iter!=list.end();++iter) orlist.push_back(*iter); } OrPattern::~OrPattern(void) { vector::iterator iter; for(iter=orlist.begin();iter!=orlist.end();++iter) delete *iter; } void OrPattern::shiftInstruction(int4 sa) { vector::iterator iter; for(iter=orlist.begin();iter!=orlist.end();++iter) (*iter)->shiftInstruction(sa); } bool OrPattern::isMatch(ParserWalker &walker) const { for(int4 i=0;iisMatch(walker)) return true; return false; } bool OrPattern::alwaysTrue(void) const { // This isn't quite right because different branches // may cover the entire gamut vector::const_iterator iter; for(iter=orlist.begin();iter!=orlist.end();++iter) if ((*iter)->alwaysTrue()) return true; return false; } bool OrPattern::alwaysFalse(void) const { vector::const_iterator iter; for(iter=orlist.begin();iter!=orlist.end();++iter) if (!(*iter)->alwaysFalse()) return false; return true; } bool OrPattern::alwaysInstructionTrue(void) const { vector::const_iterator iter; for(iter=orlist.begin();iter!=orlist.end();++iter) if (!(*iter)->alwaysInstructionTrue()) return false; return true; } Pattern *OrPattern::doAnd(const Pattern *b,int4 sa) const { const OrPattern *b2 = dynamic_cast(b); vector newlist; vector::const_iterator iter,iter2; DisjointPattern *tmp; OrPattern *tmpor; if (b2 == (const OrPattern *)0) { for(iter=orlist.begin();iter!=orlist.end();++iter) { tmp = (DisjointPattern *)(*iter)->doAnd(b,sa); newlist.push_back(tmp); } } else { for(iter=orlist.begin();iter!=orlist.end();++iter) for(iter2=b2->orlist.begin();iter2!=b2->orlist.end();++iter2) { tmp = (DisjointPattern *)(*iter)->doAnd(*iter2,sa); newlist.push_back(tmp); } } tmpor = new OrPattern(newlist); return tmpor; } Pattern *OrPattern::commonSubPattern(const Pattern *b,int4 sa) const { vector::const_iterator iter; Pattern *res,*next; iter = orlist.begin(); res = (*iter)->commonSubPattern(b,sa); iter++; if (sa > 0) sa = 0; while(iter!=orlist.end()) { next = (*iter)->commonSubPattern(res,sa); delete res; res = next; ++iter; } return res; } Pattern *OrPattern::doOr(const Pattern *b,int4 sa) const { const OrPattern *b2 = dynamic_cast(b); vector newlist; vector::const_iterator iter; for(iter=orlist.begin();iter!=orlist.end();++iter) newlist.push_back((DisjointPattern *)(*iter)->simplifyClone()); if (sa < 0) for(iter=orlist.begin();iter!=orlist.end();++iter) (*iter)->shiftInstruction(-sa); if (b2 == (const OrPattern *)0) newlist.push_back((DisjointPattern *)b->simplifyClone()); else { for(iter=b2->orlist.begin();iter!=b2->orlist.end();++iter) newlist.push_back((DisjointPattern *)(*iter)->simplifyClone()); } if (sa > 0) for(int4 i=0;ishiftInstruction(sa); OrPattern *tmpor = new OrPattern(newlist); return tmpor; } Pattern *OrPattern::simplifyClone(void) const { // Look for alwaysTrue eliminate alwaysFalse vector::const_iterator iter; for(iter=orlist.begin();iter!=orlist.end();++iter) // Look for alwaysTrue if ((*iter)->alwaysTrue()) return new InstructionPattern(true); vector newlist; for(iter=orlist.begin();iter!=orlist.end();++iter) // Look for alwaysFalse if (!(*iter)->alwaysFalse()) newlist.push_back((DisjointPattern *)(*iter)->simplifyClone()); if (newlist.empty()) return new InstructionPattern(false); else if (newlist.size() == 1) return newlist[0]; return new OrPattern(newlist); } void OrPattern::saveXml(ostream &s) const { s << "\n"; for(int4 i=0;isaveXml(s); s << "\n"; } void OrPattern::restoreXml(const Element *el) { const List &list(el->getChildren()); List::const_iterator iter; iter = list.begin(); while(iter != list.end()) { DisjointPattern *pat = DisjointPattern::restoreDisjoint(*iter); orlist.push_back(pat); ++iter; } }