Comparing OLE Objects

I have seen similar questions, but have not seen a clear answer.

I have two attributes I want to compare and return either true or false if they are different. However, it is possible some of the attributes have OLE objects contained. Is there a way to compare attributes with OLE objects?

string str1 = richTextWithOle(o."Object Text")
string str2 = richTextWithOle(o."Reviewed Text")

(not sure how to proceed from here, a simple == will obviously not work if there are OLE objects)
Thank you
MarkN_HS - Wed May 05 15:55:42 EDT 2010

Re: Comparing OLE Objects
doors36677 - Thu May 06 07:05:21 EDT 2010

Leave your email here and I will provide you with an approach forward.

Re: Comparing OLE Objects
aakhws - Thu May 06 23:01:40 EDT 2010

doors36677 - Thu May 06 07:05:21 EDT 2010
Leave your email here and I will provide you with an approach forward.

I would also like to get the approach, as I am trying to resolve the same issue.

here is my id on yahoo "aakhws"

Thanks a lot

Re: Comparing OLE Objects
SystemAdmin - Tue Feb 21 21:34:25 EST 2012

questions why won't this work? It works for me when comparing objects? Am I overlooking something with the richTextWithOle functionality that I am not aware of?
richTextWithOle(o."Object Text") == richTextWithOle(o."Reviewed Text")

-Jim

Re: Comparing OLE Objects
Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

SystemAdmin - Tue Feb 21 21:34:25 EST 2012
questions why won't this work? It works for me when comparing objects? Am I overlooking something with the richTextWithOle functionality that I am not aware of?
richTextWithOle(o."Object Text") == richTextWithOle(o."Reviewed Text")

-Jim

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 


Attachments

attachment_14792846_oleObjects.inc

Re: Comparing OLE Objects
David_G_Bond - Tue Feb 28 12:21:27 EST 2012

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

I want to thank Mathias for providing this useful tool. I have been playing around with it and am very impressed. I started to look into this and even got the OLE specification, but it was complex enough that I didn't have the time to delve into it to the extent necessary to come up with a solution.

I have run into an issue which may be of interest to others. Often users will import a file as an OLE into DOORS. For example, a figure is created or placed into a word document and then the word document is imported as an OLE. This results in an OLE embedded in an OLE. Mathias has provided functions that unlock the core data in the outer OLE, but to get to the core data of the inner OLE more work is required.

We have told our users to import the core OLEs only, but that process was not always followed. At this point in our process even "invisible" changes to objects cannot be approved. In theory, OLEs could be combined together and embedded into OLEs that are combined with other OLEs, creating a complex hierarchy of OLEs contained within OLEs. A perfect utility would systematically decode all of this and compare appropriate OLE chunks hierarchically and then pop out a "definitive" result. The simplest strategy might be to look for an embedded OLE and then create a message that basically says that the comparison is not possible, that a visual inspection is necessary, or some such approach. An intermediate approach would be to limit the digging at some point and if there is still further digging necessary, to give up and output a message telling the user that the OLE hierarchy is too complex to process.

I'll be looking into strategies to get to the "core" OLE(s) where necessary to perform a more perfect comparison, but to limit the digging at some point.

  • David Bond

Re: Comparing OLE Objects
clhoover - Tue Feb 05 11:38:20 EST 2013

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

Hi Mathias, one of my co-workers ran across this code and used it, however, before we can make it available, we need to know if there is a license and if we have permission to use. All I find is a few entries of changes you made. Can you help with this?

Re: Comparing OLE Objects
Mathias Mamsch - Wed Feb 06 08:02:18 EST 2013

clhoover - Tue Feb 05 11:38:20 EST 2013
Hi Mathias, one of my co-workers ran across this code and used it, however, before we can make it available, we need to know if there is a license and if we have permission to use. All I find is a few entries of changes you made. Can you help with this?

Any code that is posted on the Rational forum should be license free as far as I know. So feel free to use the code in any way you like.

Regards, Mathias


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Re: Comparing OLE Objects
clhoover - Wed Feb 06 13:04:52 EST 2013

Mathias Mamsch - Wed Feb 06 08:02:18 EST 2013
Any code that is posted on the Rational forum should be license free as far as I know. So feel free to use the code in any way you like.

Regards, Mathias


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

Thank you Mathias.

Re: Comparing OLE Objects
bungle_77 - Thu Jan 02 07:00:00 EST 2014

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

and how you can compare Doors pictures?

Picture are not Ole Objects?

 

    string picfatherFilename = getPictName(o_Father)

    if (!null picFilename) {
        string picsonFilename = getPictName(o_Son)
        if (picfatherFilename != picsonFilename) {
            return "False"                
        }
    }

 

Like this?

 

For comparing OleObject is not enough to compare the length ?

Re: Comparing OLE Objects
Mathias Mamsch - Thu Jan 02 12:43:22 EST 2014

bungle_77 - Thu Jan 02 07:00:00 EST 2014

and how you can compare Doors pictures?

Picture are not Ole Objects?

 

    string picfatherFilename = getPictName(o_Father)

    if (!null picFilename) {
        string picsonFilename = getPictName(o_Son)
        if (picfatherFilename != picsonFilename) {
            return "False"                
        }
    }

 

Like this?

 

For comparing OleObject is not enough to compare the length ?

For OLE objects it is a good first step to compare the length of the OLE to check if there has been a change. So if there is a length change (as with pictures) there is a definitive change. However it is easy to think about cases where the OLE object length stays the same, while the content is different. Think about two pictures with the same size and different content. In real life this is of course seldom but thinkable. So it is really a question if you need 100% security in comparison.

So to compare pictures it is also not enough to compare the picture filenames. I ended up using openPictFile to get a Stream to the picture files, first comparing the length of the pictures (using a Stat on the Stream) and only if the picture sizes are equal comparing the picture data char by char (be aware of null characters, which will not allow you to read the full data of a picture to a buffer).

Regards, Mathias

Re: Comparing OLE Objects
bungle_77 - Fri Jan 03 04:37:44 EST 2014

Mathias Mamsch - Thu Jan 02 12:43:22 EST 2014

For OLE objects it is a good first step to compare the length of the OLE to check if there has been a change. So if there is a length change (as with pictures) there is a definitive change. However it is easy to think about cases where the OLE object length stays the same, while the content is different. Think about two pictures with the same size and different content. In real life this is of course seldom but thinkable. So it is really a question if you need 100% security in comparison.

So to compare pictures it is also not enough to compare the picture filenames. I ended up using openPictFile to get a Stream to the picture files, first comparing the length of the pictures (using a Stat on the Stream) and only if the picture sizes are equal comparing the picture data char by char (be aware of null characters, which will not allow you to read the full data of a picture to a buffer).

Regards, Mathias

Thanks a lot Mathias for your explanation, it was very precious!

my problem is that i have to make the comparison  of n attributes in the code of a DXL attribute so the computation can't be too heavy.

Reading all the threads about this topic i am realizing you need to make a very complext comparison and you can't be 100% sure to detect the change.

In my case in the 99% of the case the objects to compare are identical because i compare a requirement and a clone of a requirement.

I am evaluating if it's enough to compare the length of the olebjects (obviously after a check on the text) being aware of the risk that i can't detect the change in the 1% of the cases.

Do you think is implementable all your comparison in a DXL Attribute?

If i have the constraint that the OleObject shall be only single picture, with the code you wrote above can i be 100% sure to detect everything?

Re: Comparing OLE Objects
Mathias Mamsch - Sat Jan 04 15:47:41 EST 2014

bungle_77 - Fri Jan 03 04:37:44 EST 2014

Thanks a lot Mathias for your explanation, it was very precious!

my problem is that i have to make the comparison  of n attributes in the code of a DXL attribute so the computation can't be too heavy.

Reading all the threads about this topic i am realizing you need to make a very complext comparison and you can't be 100% sure to detect the change.

In my case in the 99% of the case the objects to compare are identical because i compare a requirement and a clone of a requirement.

I am evaluating if it's enough to compare the length of the olebjects (obviously after a check on the text) being aware of the risk that i can't detect the change in the 1% of the cases.

Do you think is implementable all your comparison in a DXL Attribute?

If i have the constraint that the OleObject shall be only single picture, with the code you wrote above can i be 100% sure to detect everything?

Regarding the detection of changes:

  1. The code above will give you 100% for visible differences, e.g. all OLE changes, that will result in a different picture (which is when you think about a printed document most of the time what you want)
  2. The length comparison is useless, when you have no changes, i.e. all unchanged attribute values will have no length change, therefore you will not get a large speed benefit from this.
  3. The length comparison is however a short cut for eliminating the comparison for OLE objects 90% of the time, because most OLE object changes, will change the length of an OLE object.
  4. Extracting and comparing the picture part of the OLE object is not a heavy operation. It is just applying a regex, a substring and a buffer compare. So it really has no speed impact.
  5. For picture comparison the length comparison is a real life saver, since the character by character comparison is really slow. Also you should know that the openPictFile like every Stream open operation will leak a Stream Handle, which makes your DXL slower if it happens a lot. However in practice you should not have so many pictures in modules, so again there is not a huge speed impact.

Regarding the use of DXL Attributes. I would not use them for this purpose. You need to have write access to the module to create it and it will lock the module for quite some time when opening. With BranchManager we use a GUI-Backed layout DXL for this purpose and a timer for the calculation of the comparison. This allows you to calculate the comparison in background, the user does not need to wait, you can also use it in read only mode, etc. You can read over it here:

https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014890784#77777777-0000-0000-0000-000014891453

Here is a more involved example (for the code comments see the original post):

string colCode (string sFileName) 
{ 
    Buffer bufFile = create() 
    
    int i; for (i = 0; i < length sFileName; i++) { 
      if (sFileName[i] == '\\') bufFile += "\\" 
      bufFile += sFileName[i] 
    }
    string sResult = "
noError() 
// read the memory address from the file
Stream x = read \"" (stringOf bufFile) "\"
lastError()   
// if the file exists we will get a Stream here 
if (!null x) { 
    // read the memory address 
    int adSkip = 0 
    x >> adSkip 
    
    if (adSkip != 0) 
    { 
      Skip sk = addr_ adSkip   
  
      int nr = obj. \"Absolute Number\"  
      string sDisplayVal = \"\" 
      if (find (sk, nr, sDisplayVal)) { 
          display sDisplayVal 
      } 
    } else {
      // now what?  
    }   
} else { 
   // You might want to show some dummy text here, 
   // that the cache does not exist 
} 
" 
    
    delete bufFile 
    
    return sResult 
}   

// This is our cache. Key = AbsNo  Value = string to display 
Skip skBuffer = create()   
string sCacheFileName = tempFileName ()   

Stream x = write sCacheFileName 
x << ((addr_ skBuffer) int) "" 
close x     

Column c = insert column 0 // insert column  

dxl (c, colCode(sCacheFileName) )
title(c, "GUI Backed Layout DXL")

void onClose (DB x) { 
   deleteFile sCacheFileName 
   hide x 
   // delete the column, or let it show its dummy text  
   delete c 
}

bool bPause = false;
void btPauseCallback (DB x) {
   bPause = !bPause;
}

// Make a skip with all object in it
Skip skObjects = create(); 
int iCount = 0, iCurrent = 0; Object o; 
for o in entire current Module do put(skObjects, iCount++, o)

// ***************** Put your calculation for Object o here ***************
int gCount = 0
string doCalculation (Object o) {
   string sResult = "Hi I am Object " (o."Absolute Number") " and I was updated at " (gCount++) "!\n"
   return sResult
}
// ************************************************************************


// This timer callback is responsible for background processing
void timerCallback(DBE x) {
   // to be able to process more than one object for each timer call
   // we measure the time and stop processing after 50% of the timer
   // callback time (100 ms - 50ms = 50ms)
   int iStartTime = getTickCount_() 

   iCurrent ++
   // uncomment this if you only want to calculate each object once
   // if (iCurrent >= iCount) return

   // process pause state
   if (bPause) return 

   // in the example we use this for recalculating from start, 
   // once we finished calculation for each object
   iCurrent = iCurrent % iCount;

   // work for 50 ms
   while (getTickCount_() - iStartTime < 50) {
      // get the object for the calculation
      Object oCurrent = null
      if (find (skObjects, iCurrent, oCurrent)) { 
          int nr = oCurrent."Absolute Number"
          string s = doCalculation(oCurrent);
          put (skBuffer, nr, s, true);
      } else {
          // wtf?
      }
   }

   // we use this to interactively refresh the calculation because
   // otherwise layout DXL is only updated on each click
   // you dont need this, you can also apply some tricks here
   // to check if the object is visible and only refresh in this case
   refresh (current Module)
}

DB gui = centered "Calculating ... "

timer(gui, 0.1, timerCallback, "Calculation")
apply(gui, "Pause", btPauseCallback)
close (gui, true, onClose)
realize gui
setSize(gui, 300, 100)
show gui

Hope that helps, regards, Mathias

Re: Comparing OLE Objects
bungle_77 - Tue Jan 07 05:36:59 EST 2014

Mathias Mamsch - Sat Jan 04 15:47:41 EST 2014

Regarding the detection of changes:

  1. The code above will give you 100% for visible differences, e.g. all OLE changes, that will result in a different picture (which is when you think about a printed document most of the time what you want)
  2. The length comparison is useless, when you have no changes, i.e. all unchanged attribute values will have no length change, therefore you will not get a large speed benefit from this.
  3. The length comparison is however a short cut for eliminating the comparison for OLE objects 90% of the time, because most OLE object changes, will change the length of an OLE object.
  4. Extracting and comparing the picture part of the OLE object is not a heavy operation. It is just applying a regex, a substring and a buffer compare. So it really has no speed impact.
  5. For picture comparison the length comparison is a real life saver, since the character by character comparison is really slow. Also you should know that the openPictFile like every Stream open operation will leak a Stream Handle, which makes your DXL slower if it happens a lot. However in practice you should not have so many pictures in modules, so again there is not a huge speed impact.

Regarding the use of DXL Attributes. I would not use them for this purpose. You need to have write access to the module to create it and it will lock the module for quite some time when opening. With BranchManager we use a GUI-Backed layout DXL for this purpose and a timer for the calculation of the comparison. This allows you to calculate the comparison in background, the user does not need to wait, you can also use it in read only mode, etc. You can read over it here:

https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014890784#77777777-0000-0000-0000-000014891453

Here is a more involved example (for the code comments see the original post):

string colCode (string sFileName) 
{ 
    Buffer bufFile = create() 
    
    int i; for (i = 0; i < length sFileName; i++) { 
      if (sFileName[i] == '\\') bufFile += "\\" 
      bufFile += sFileName[i] 
    }
    string sResult = "
noError() 
// read the memory address from the file
Stream x = read \"" (stringOf bufFile) "\"
lastError()   
// if the file exists we will get a Stream here 
if (!null x) { 
    // read the memory address 
    int adSkip = 0 
    x >> adSkip 
    
    if (adSkip != 0) 
    { 
      Skip sk = addr_ adSkip   
  
      int nr = obj. \"Absolute Number\"  
      string sDisplayVal = \"\" 
      if (find (sk, nr, sDisplayVal)) { 
          display sDisplayVal 
      } 
    } else {
      // now what?  
    }   
} else { 
   // You might want to show some dummy text here, 
   // that the cache does not exist 
} 
" 
    
    delete bufFile 
    
    return sResult 
}   

// This is our cache. Key = AbsNo  Value = string to display 
Skip skBuffer = create()   
string sCacheFileName = tempFileName ()   

Stream x = write sCacheFileName 
x << ((addr_ skBuffer) int) "" 
close x     

Column c = insert column 0 // insert column  

dxl (c, colCode(sCacheFileName) )
title(c, "GUI Backed Layout DXL")

void onClose (DB x) { 
   deleteFile sCacheFileName 
   hide x 
   // delete the column, or let it show its dummy text  
   delete c 
}

bool bPause = false;
void btPauseCallback (DB x) {
   bPause = !bPause;
}

// Make a skip with all object in it
Skip skObjects = create(); 
int iCount = 0, iCurrent = 0; Object o; 
for o in entire current Module do put(skObjects, iCount++, o)

// ***************** Put your calculation for Object o here ***************
int gCount = 0
string doCalculation (Object o) {
   string sResult = "Hi I am Object " (o."Absolute Number") " and I was updated at " (gCount++) "!\n"
   return sResult
}
// ************************************************************************


// This timer callback is responsible for background processing
void timerCallback(DBE x) {
   // to be able to process more than one object for each timer call
   // we measure the time and stop processing after 50% of the timer
   // callback time (100 ms - 50ms = 50ms)
   int iStartTime = getTickCount_() 

   iCurrent ++
   // uncomment this if you only want to calculate each object once
   // if (iCurrent >= iCount) return

   // process pause state
   if (bPause) return 

   // in the example we use this for recalculating from start, 
   // once we finished calculation for each object
   iCurrent = iCurrent % iCount;

   // work for 50 ms
   while (getTickCount_() - iStartTime < 50) {
      // get the object for the calculation
      Object oCurrent = null
      if (find (skObjects, iCurrent, oCurrent)) { 
          int nr = oCurrent."Absolute Number"
          string s = doCalculation(oCurrent);
          put (skBuffer, nr, s, true);
      } else {
          // wtf?
      }
   }

   // we use this to interactively refresh the calculation because
   // otherwise layout DXL is only updated on each click
   // you dont need this, you can also apply some tricks here
   // to check if the object is visible and only refresh in this case
   refresh (current Module)
}

DB gui = centered "Calculating ... "

timer(gui, 0.1, timerCallback, "Calculation")
apply(gui, "Pause", btPauseCallback)
close (gui, true, onClose)
realize gui
setSize(gui, 300, 100)
show gui

Hope that helps, regards, Mathias

thanks a lot Mathias, your post is really precious!

Re: Comparing OLE Objects
llandale - Tue Jan 07 16:24:55 EST 2014

bungle_77 - Thu Jan 02 07:00:00 EST 2014

and how you can compare Doors pictures?

Picture are not Ole Objects?

 

    string picfatherFilename = getPictName(o_Father)

    if (!null picFilename) {
        string picsonFilename = getPictName(o_Son)
        if (picfatherFilename != picsonFilename) {
            return "False"                
        }
    }

 

Like this?

 

For comparing OleObject is not enough to compare the length ?

Length of Picture is good enough.  Length of OLE I think is not good enough since someone can reasonably open the OLE object and change "This" to "That" without any change in length.

Byte-by-Byte checks I think will fail for both, even when there is no actual change.  IIRC years ago, I would copy and OLE, paste to another object, then compare them byte-by-byte and they were not the same.  I think it was due to "empty" space in the OLE that gets whatever happens to be in memory or disk at the time of the read.

I went through this several years ago and gave up; using a glorified "Last Modified On" approach to figure out if two objecs that were originally identical still were.  I found that I never failed to detect a change but I did indeed detect "changes" that didn't actually change anything (since you can "edit" an attr-value and save it, even if you don't actually make a change; and of course you can change and then change back).

I would also like to point out that can, if need be, do this:

  • Copy the Original Obj-Attr-Value onto the copy.
  • See if the Object has changed, perhaps with LastModifiedOn  or History values.
  • Close without saving.

-Louie

Re: Comparing OLE Objects
Mathias Mamsch - Wed Jan 08 04:01:17 EST 2014

llandale - Tue Jan 07 16:24:55 EST 2014

Length of Picture is good enough.  Length of OLE I think is not good enough since someone can reasonably open the OLE object and change "This" to "That" without any change in length.

Byte-by-Byte checks I think will fail for both, even when there is no actual change.  IIRC years ago, I would copy and OLE, paste to another object, then compare them byte-by-byte and they were not the same.  I think it was due to "empty" space in the OLE that gets whatever happens to be in memory or disk at the time of the read.

I went through this several years ago and gave up; using a glorified "Last Modified On" approach to figure out if two objecs that were originally identical still were.  I found that I never failed to detect a change but I did indeed detect "changes" that didn't actually change anything (since you can "edit" an attr-value and save it, even if you don't actually make a change; and of course you can change and then change back).

I would also like to point out that can, if need be, do this:

  • Copy the Original Obj-Attr-Value onto the copy.
  • See if the Object has changed, perhaps with LastModifiedOn  or History values.
  • Close without saving.

-Louie

Hi Louie... Byte by Byte comparison works - for the picture part of an OLE object as well as for DOORS Picture objects. I think the problem of random data only applies to the data part of an OLE object, that means static metafiles embedded as OLE object should also not change. Do you have an example that shows differently?

I would also be careful with uncompressed pictures (e.g. bmp), because their size only dependes on their dimensions. So a length comparison will fail as long as the changed picture stays the same size. 

Last Modified on works well for comparing baselines inside the same module, however for two modules it is more difficult because both objects could actually have changed. Also take care with attributes that have/had the last modification date turned off (I know, who does something like that?).

Regards, Mathias

Re: Comparing OLE Objects
llandale - Wed Jan 08 11:50:39 EST 2014

Mathias Mamsch - Wed Jan 08 04:01:17 EST 2014

Hi Louie... Byte by Byte comparison works - for the picture part of an OLE object as well as for DOORS Picture objects. I think the problem of random data only applies to the data part of an OLE object, that means static metafiles embedded as OLE object should also not change. Do you have an example that shows differently?

I would also be careful with uncompressed pictures (e.g. bmp), because their size only dependes on their dimensions. So a length comparison will fail as long as the changed picture stays the same size. 

Last Modified on works well for comparing baselines inside the same module, however for two modules it is more difficult because both objects could actually have changed. Also take care with attributes that have/had the last modification date turned off (I know, who does something like that?).

Regards, Mathias

Don't understand nuance of "picture part" vis-a-vis "data part" of the OLE.  I was getting a handle on the EmbeddedOleObject, then reading into a Buffer.  I was definately not "opening" the OLE and peeking inside.

Effort to find out if OLE changed was 11 years ago.  My observations above WERE valid but perhaps no longer.  As I said I gave up and used a glorified LastModifiedOn approach, which included adding a date attribute to the 2nd module "LastVerifiedOn" or something like that.  I didn't have a both-objects-changing issue since the target (in my case) was hard locked down. 

Anyway, looks like there is no reasonably perfect solution.

-Louie

Re: Comparing OLE Objects
dacapri - Tue Jan 28 03:34:51 EST 2014

Wow, this is the endless story.

1)      Do we know how functions like "Tools -> compare modules" or ""Exchange module" are working?

          I mean, are they able to detect correctly changes within OLE?

2)      Is there any way to contact IBM or to open them a ticket for future improvements/updates?

 

Regards,

Daniele

Re: Comparing OLE Objects
Mathias Mamsch - Tue Jan 28 14:00:44 EST 2014

dacapri - Tue Jan 28 03:34:51 EST 2014

Wow, this is the endless story.

1)      Do we know how functions like "Tools -> compare modules" or ""Exchange module" are working?

          I mean, are they able to detect correctly changes within OLE?

2)      Is there any way to contact IBM or to open them a ticket for future improvements/updates?

 

Regards,

Daniele

1) We know how they work, they do not compare OLE data ... Sometimes they compare modification dates.However the above approach for comparing OLE objects works! So you can detect changes to OLE objects very reliably and fast.

2. Of course. Somebody should create a PR for DOORS with highst priority and title it "DOORS client is changing baselined data" ... Then take the example code here from the forum that proves that when you read the same OLE object from a module several times that you get a different RTF from time to time. The argument would be that baselined data must not change ever. Any argument from IBM about how the DOORS client is not responsible, but Windows or whatever should be met with the argument, that this is about writing RTF to an attribute and getting the same RTF back when you read it.

I really wonder if nobody ever created a PR for that and I highly doubt that this is a complex problem to solve on the client side. So my conclusion is, that most people simply do not bother enough about that problem for it to be fixed.

Regards, Mathias

Re: Comparing OLE Objects
dacapri - Thu Jan 30 03:05:37 EST 2014

Mathias Mamsch - Tue Jan 28 14:00:44 EST 2014

1) We know how they work, they do not compare OLE data ... Sometimes they compare modification dates.However the above approach for comparing OLE objects works! So you can detect changes to OLE objects very reliably and fast.

2. Of course. Somebody should create a PR for DOORS with highst priority and title it "DOORS client is changing baselined data" ... Then take the example code here from the forum that proves that when you read the same OLE object from a module several times that you get a different RTF from time to time. The argument would be that baselined data must not change ever. Any argument from IBM about how the DOORS client is not responsible, but Windows or whatever should be met with the argument, that this is about writing RTF to an attribute and getting the same RTF back when you read it.

I really wonder if nobody ever created a PR for that and I highly doubt that this is a complex problem to solve on the client side. So my conclusion is, that most people simply do not bother enough about that problem for it to be fixed.

Regards, Mathias

Thank you Mathias.

I'll first implement your solution and let's see if it will be enough for me.

My IBM ID cannot open a PMR,so let's see if somebody else can do it.

A colleague of mine wrote to IBM time ago about this problem and they said something like "we know and that's it". :/

 

Keep in touch.

 

Bye,
Daniele

Re: Comparing OLE Objects
bungle_77 - Mon Feb 03 10:14:40 EST 2014

Mathias Mamsch - Sat Jan 04 15:47:41 EST 2014

Regarding the detection of changes:

  1. The code above will give you 100% for visible differences, e.g. all OLE changes, that will result in a different picture (which is when you think about a printed document most of the time what you want)
  2. The length comparison is useless, when you have no changes, i.e. all unchanged attribute values will have no length change, therefore you will not get a large speed benefit from this.
  3. The length comparison is however a short cut for eliminating the comparison for OLE objects 90% of the time, because most OLE object changes, will change the length of an OLE object.
  4. Extracting and comparing the picture part of the OLE object is not a heavy operation. It is just applying a regex, a substring and a buffer compare. So it really has no speed impact.
  5. For picture comparison the length comparison is a real life saver, since the character by character comparison is really slow. Also you should know that the openPictFile like every Stream open operation will leak a Stream Handle, which makes your DXL slower if it happens a lot. However in practice you should not have so many pictures in modules, so again there is not a huge speed impact.

Regarding the use of DXL Attributes. I would not use them for this purpose. You need to have write access to the module to create it and it will lock the module for quite some time when opening. With BranchManager we use a GUI-Backed layout DXL for this purpose and a timer for the calculation of the comparison. This allows you to calculate the comparison in background, the user does not need to wait, you can also use it in read only mode, etc. You can read over it here:

https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014890784#77777777-0000-0000-0000-000014891453

Here is a more involved example (for the code comments see the original post):

string colCode (string sFileName) 
{ 
    Buffer bufFile = create() 
    
    int i; for (i = 0; i < length sFileName; i++) { 
      if (sFileName[i] == '\\') bufFile += "\\" 
      bufFile += sFileName[i] 
    }
    string sResult = "
noError() 
// read the memory address from the file
Stream x = read \"" (stringOf bufFile) "\"
lastError()   
// if the file exists we will get a Stream here 
if (!null x) { 
    // read the memory address 
    int adSkip = 0 
    x >> adSkip 
    
    if (adSkip != 0) 
    { 
      Skip sk = addr_ adSkip   
  
      int nr = obj. \"Absolute Number\"  
      string sDisplayVal = \"\" 
      if (find (sk, nr, sDisplayVal)) { 
          display sDisplayVal 
      } 
    } else {
      // now what?  
    }   
} else { 
   // You might want to show some dummy text here, 
   // that the cache does not exist 
} 
" 
    
    delete bufFile 
    
    return sResult 
}   

// This is our cache. Key = AbsNo  Value = string to display 
Skip skBuffer = create()   
string sCacheFileName = tempFileName ()   

Stream x = write sCacheFileName 
x << ((addr_ skBuffer) int) "" 
close x     

Column c = insert column 0 // insert column  

dxl (c, colCode(sCacheFileName) )
title(c, "GUI Backed Layout DXL")

void onClose (DB x) { 
   deleteFile sCacheFileName 
   hide x 
   // delete the column, or let it show its dummy text  
   delete c 
}

bool bPause = false;
void btPauseCallback (DB x) {
   bPause = !bPause;
}

// Make a skip with all object in it
Skip skObjects = create(); 
int iCount = 0, iCurrent = 0; Object o; 
for o in entire current Module do put(skObjects, iCount++, o)

// ***************** Put your calculation for Object o here ***************
int gCount = 0
string doCalculation (Object o) {
   string sResult = "Hi I am Object " (o."Absolute Number") " and I was updated at " (gCount++) "!\n"
   return sResult
}
// ************************************************************************


// This timer callback is responsible for background processing
void timerCallback(DBE x) {
   // to be able to process more than one object for each timer call
   // we measure the time and stop processing after 50% of the timer
   // callback time (100 ms - 50ms = 50ms)
   int iStartTime = getTickCount_() 

   iCurrent ++
   // uncomment this if you only want to calculate each object once
   // if (iCurrent >= iCount) return

   // process pause state
   if (bPause) return 

   // in the example we use this for recalculating from start, 
   // once we finished calculation for each object
   iCurrent = iCurrent % iCount;

   // work for 50 ms
   while (getTickCount_() - iStartTime < 50) {
      // get the object for the calculation
      Object oCurrent = null
      if (find (skObjects, iCurrent, oCurrent)) { 
          int nr = oCurrent."Absolute Number"
          string s = doCalculation(oCurrent);
          put (skBuffer, nr, s, true);
      } else {
          // wtf?
      }
   }

   // we use this to interactively refresh the calculation because
   // otherwise layout DXL is only updated on each click
   // you dont need this, you can also apply some tricks here
   // to check if the object is visible and only refresh in this case
   refresh (current Module)
}

DB gui = centered "Calculating ... "

timer(gui, 0.1, timerCallback, "Calculation")
apply(gui, "Pause", btPauseCallback)
close (gui, true, onClose)
realize gui
setSize(gui, 300, 100)
show gui

Hope that helps, regards, Mathias

i have a problem, i do this instruction:

o_Son."Object Text"=richTextWithOle(o_Father."Object Text")

after this instruction if I check the lengths of o_Son."Object Text" e o_Father."Object Text" , they are not the same.

How is it possible?

 

the defference it seems to be the tag "\lang1040" that there is only in o_Son

Re: Comparing OLE Objects
Mathias Mamsch - Mon Feb 03 17:59:09 EST 2014

bungle_77 - Mon Feb 03 10:14:40 EST 2014

i have a problem, i do this instruction:

o_Son."Object Text"=richTextWithOle(o_Father."Object Text")

after this instruction if I check the lengths of o_Son."Object Text" e o_Father."Object Text" , they are not the same.

How is it possible?

 

the defference it seems to be the tag "\lang1040" that there is only in o_Son

DOORS actively analyses and changes richtext that you assign to an attribute. During this it tries to correct invalid, incomplete or unsupported richtext. If you only assign for example  richText "{\b ABC}"  (which is not a valid richtext document) DOORS will wrap this automatically in a "{\rtf1\..." header for you. If you concatenate two richtext documents DOORS will also magically know how to display this richtext. 

Therefore it can be expected that the assignment of a string richText will not yield exactly the same result when reading it again.

However you may want to try with:

set( o_Son."Object Text", o_Father."Object Text")

if it also shows this behaviour.

Regards, Mathias

Re: Comparing OLE Objects
bungle_77 - Tue Feb 04 04:23:14 EST 2014

Mathias Mamsch - Mon Feb 03 17:59:09 EST 2014

DOORS actively analyses and changes richtext that you assign to an attribute. During this it tries to correct invalid, incomplete or unsupported richtext. If you only assign for example  richText "{\b ABC}"  (which is not a valid richtext document) DOORS will wrap this automatically in a "{\rtf1\..." header for you. If you concatenate two richtext documents DOORS will also magically know how to display this richtext. 

Therefore it can be expected that the assignment of a string richText will not yield exactly the same result when reading it again.

However you may want to try with:

set( o_Son."Object Text", o_Father."Object Text")

if it also shows this behaviour.

Regards, Mathias

great it works fine.

Thanks again

Re: Comparing OLE Objects
bungle_77 - Fri Mar 14 05:39:45 EDT 2014

Mathias Mamsch - Mon Feb 03 17:59:09 EST 2014

DOORS actively analyses and changes richtext that you assign to an attribute. During this it tries to correct invalid, incomplete or unsupported richtext. If you only assign for example  richText "{\b ABC}"  (which is not a valid richtext document) DOORS will wrap this automatically in a "{\rtf1\..." header for you. If you concatenate two richtext documents DOORS will also magically know how to display this richtext. 

Therefore it can be expected that the assignment of a string richText will not yield exactly the same result when reading it again.

However you may want to try with:

set( o_Son."Object Text", o_Father."Object Text")

if it also shows this behaviour.

Regards, Mathias

is it possible to use the "set" instruction in append?

i have several object text with ole that i have to concatenate in one object text

Re: Comparing OLE Objects
EHcnck - Tue Feb 03 11:27:17 EST 2015

dacapri - Thu Jan 30 03:05:37 EST 2014

Thank you Mathias.

I'll first implement your solution and let's see if it will be enough for me.

My IBM ID cannot open a PMR,so let's see if somebody else can do it.

A colleague of mine wrote to IBM time ago about this problem and they said something like "we know and that's it". :/

 

Keep in touch.

 

Bye,
Daniele

Hello,

Is there a way to visually show the differences of OLE objects?

 

Re: Comparing OLE Objects
Wolfgang Uhr - Thu Feb 05 02:02:26 EST 2015

EHcnck - Tue Feb 03 11:27:17 EST 2015

Hello,

Is there a way to visually show the differences of OLE objects?

 

Hi

> Is there a way to visually show the differences of OLE objects?

If you mean "Deltas insid the object", then the answer is no, because this deltas can only be evaluated by the programm which has created the ole-object or by a programm which can handle that file format.

Such a function inside of doors is impossible, otherwise doors should provide a diff-viewer for more than 100 file formats.

Best regards

Wolfgang

Re: Comparing OLE Objects
Mathias Mamsch - Mon Feb 09 06:32:19 EST 2015

EHcnck - Tue Feb 03 11:27:17 EST 2015

Hello,

Is there a way to visually show the differences of OLE objects?

 

If by visual comparison you mean something like "it shows you both objects and highlights the differences in the picture for you"  then the answer is of course NO.

You could of course for every type of OLE object code your own "comparison", e.g. take the one OLE object. Store it to a file. Take the second one. Open it. Invoke Word Comparison with the first one. Display the result as a new OLE object.

Or you might not want to do that.

Regards, Mathias

Re: Comparing OLE Objects
Wolfgang Uhr - Mon Feb 09 10:47:10 EST 2015

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

> Until someone pressures me this change is left as an excercise for the reader.

May be our chances are sligtly better, if we find a windows api which handles the stuff. Otherwiese we will have the same problem in the next windows version, isn't it?

Re: Comparing OLE Objects
Mathias Mamsch - Mon Feb 09 11:42:26 EST 2015

Wolfgang Uhr - Mon Feb 09 10:47:10 EST 2015

> Until someone pressures me this change is left as an excercise for the reader.

May be our chances are sligtly better, if we find a windows api which handles the stuff. Otherwiese we will have the same problem in the next windows version, isn't it?

Well I guess its more about parsing the OLE object better, than by a single regular expression that assumes an exact representation. As long as we parse the object according to the RTF specification, then we are not dependent on the windows API. But in that very old file there is just a regexp that would assume the representation of an OLE in an exact sequence of control words - and these changed from one RTF component to another.

Regards, Mathias

Re: Comparing OLE Objects
EHcnck - Fri Jul 29 16:11:29 EDT 2016

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

Just was wondering if happened to update this for the latest version of DOORS? Thank you.

Re: Comparing OLE Objects
Mathias Mamsch - Mon Aug 01 02:27:58 EDT 2016

EHcnck - Fri Jul 29 16:11:29 EDT 2016

Just was wondering if happened to update this for the latest version of DOORS? Thank you.

No. But a fix is easy to apply. Just make a small OLE Object inside a module, and print its richtext ( print richTextWithOle (current Object)."Object Text" ) You will get something like: 

{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\f0\fs20
{
\object\objemb{\*\objclass Package}\objw795\objh810{\*\objdata 
....


{\result{\pict\wmetafile8\picw795\pich810\picwgoal795\pichgoal810 
0100090000033b0700000200210600000000050000000b0200000000050000000c02350034001c
...

Now notice the regular expressions on top of the code: 

string reHeader = "{\\\\object\\\\objemb{\\\\\\*\\\\objclass ([^}]+)}\\\\objw([^\\\\{}]+)\\\\objh([^\\\\{}]+)" 

string picData = "([^}]+)"   
string picHeader = "{\\\\pict\\\\([^\\\\]+)(\\\\picw([^\\\\{}]+))?(\\\\pich([^\\\\]+))?\\\\picwgoal([-0-9]+)\\\\pichgoal([-0-9]+)" 

As long as the regexps match, the code should work fine. If the regexps do not match, you need to extend them.

The permanent fix for the issue would be to parse the tags of the picture / object rtf according to the RTF spec, rather than using a simple regexp for parsing the information. 

Maybe this helps, regards, Mathias

Re: Comparing OLE Objects
Wolfgang Uhr - Mon Aug 01 04:40:06 EDT 2016

EHcnck - Tue Feb 03 11:27:17 EST 2015

Hello,

Is there a way to visually show the differences of OLE objects?

 

Inside of doors I think the routine is named bufCompare or bufferCompare
 

Re: Comparing OLE Objects
EHcnck - Tue Sep 26 15:18:23 EDT 2017

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

using your code just activating the ole shows as different, is this correct?

Re: Comparing OLE Objects
Mathias Mamsch - Tue Sep 26 15:23:47 EDT 2017

EHcnck - Tue Sep 26 15:18:23 EDT 2017

using your code just activating the ole shows as different, is this correct?

The code will compare the picture data of the OLE objects, so you just get the information "equal" or "not equal" which is solely based on the attribute value buffer. You do not need to show or activate the OLE object to compare this part of the attribute value. You will not get a "diff" though - if you want to know WHAT is different you need to visually compare the pictures side by side. Regards, Mathias

Re: Comparing OLE Objects
EHcnck - Tue Sep 26 15:30:27 EDT 2017

Mathias Mamsch - Tue Sep 26 15:23:47 EDT 2017

The code will compare the picture data of the OLE objects, so you just get the information "equal" or "not equal" which is solely based on the attribute value buffer. You do not need to show or activate the OLE object to compare this part of the attribute value. You will not get a "diff" though - if you want to know WHAT is different you need to visually compare the pictures side by side. Regards, Mathias

No what I'm trying to ask is ... by simply activating the OLE nothing else shows the OLE as changed is this the correct behavior? 

Re: Comparing OLE Objects
Mathias Mamsch - Tue Sep 26 15:57:39 EDT 2017

EHcnck - Tue Sep 26 15:30:27 EDT 2017

No what I'm trying to ask is ... by simply activating the OLE nothing else shows the OLE as changed is this the correct behavior? 

If I understand you correctly you are asking if it is normal behaviour that you cannot find any difference (e.g. after activating the OLE without making changes), although the code tells you there is a difference. That is possible. After all the code compares the picture data of the OLE object and sometimes you get a small shift of the picture, the picture gets a little larger, some unimportant detail of the picture changes. This will all result in a difference, although there might be no content difference. Without going in the specifics of each OLE application, this is as far as you get. If activating the OLE changes the attribute value, then you changed the OLE. Regards, Mathias

Re: Comparing OLE Objects
ckulkarni - Wed Jul 18 02:34:23 EDT 2018

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

Hello Mathias,

Thank you for the code you shared for OLE object comparison.

I tried the same code to extract the data part and the picture part of the OLE object.

I can extract data part correctly as you have given

val = s [match 5]             ; x->m_data      = val

 

But picture part extraction as given below, will not extract the complete Picture data.

val = s [match 7]            ; x->m_picture   = val

 

It only extract     "{\pict{\*\picprop

I expected it to extract as below

{\result{\pict{\*\picprop}\wmetafile8\picw975\pich810\picwgoal975\pichgoal810
0100090000033a0700000200210600000000050000000b0200000000050000000c02350040001c
000000fb02f4ff000000000000900100000001000005005365676f65205549007659757c240aec ..... }

If this gets extracted completely , then only the code below can be used to extract the picture part.

 

        if (rePic val) {        
            val = val [match 8]  ; x->m_picturedata = val
            // print "Picture:" val "\n"
        } else {
            val = create()
            x->m_picturedata = val
        }

Can you please help in this regard, am i going wrong in understanding the code/regexp?

 

 

Re: Comparing OLE Objects
Mathias Mamsch - Wed Jul 18 03:12:45 EDT 2018

ckulkarni - Wed Jul 18 02:34:23 EDT 2018

Hello Mathias,

Thank you for the code you shared for OLE object comparison.

I tried the same code to extract the data part and the picture part of the OLE object.

I can extract data part correctly as you have given

val = s [match 5]             ; x->m_data      = val

 

But picture part extraction as given below, will not extract the complete Picture data.

val = s [match 7]            ; x->m_picture   = val

 

It only extract     "{\pict{\*\picprop

I expected it to extract as below

{\result{\pict{\*\picprop}\wmetafile8\picw975\pich810\picwgoal975\pichgoal810
0100090000033a0700000200210600000000050000000b0200000000050000000c02350040001c
000000fb02f4ff000000000000900100000001000005005365676f65205549007659757c240aec ..... }

If this gets extracted completely , then only the code below can be used to extract the picture part.

 

        if (rePic val) {        
            val = val [match 8]  ; x->m_picturedata = val
            // print "Picture:" val "\n"
        } else {
            val = create()
            x->m_picturedata = val
        }

Can you please help in this regard, am i going wrong in understanding the code/regexp?

 

 

Well as far as I can see, the regexp in the code is listed as follows:

string picHeader = "{\\\\pict\\\\([^\\\\]+)(\\\\picw([^\\\\{}]+))?(\\\\pich([^\\\\]+))?\\\\picwgoal([-0-9]+)\\\\pichgoal([-0-9]+)" 
string picData = "([^}]+)"   

Your picture data is:

{\pict{\*\picprop}\wmetafile8\picw975\pich810\picwgoal975\pichgoal810
0100090000033a0700000200210600000000050000000b0200000000050000000c02350040001c
000000fb02f4ff000000000000900100000001000005005365676f65205549007659757c240aec ..... }

As described in the big fat red header, the regular expression needs to be changed, since DOORS has changed its RTF engine since then (or is using the Windows default one which has changed). In your case it does not seem to match the "\*\picprop" element, so it will parse only until \pict { and then then picData will parse the \*\picprop up to the last "}" ... So changing the regexp will work, however it is only a temporary solution. I still wait for somebody to step in, take for example the RTF Tokenizer I made here:

https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014923264&ps=25

and rewrite the OLE Parser to be able to handle any picture / OLE control words in the header and still be able to parse the OLE to the end. Because when you use a regexp, you always apply an order of the control words and any additional control word in the picture will break the parsing which is kind of bad. Maybe you are the one to rewrite the code to be more stable and post it back here? :-)

Regards, Mathias

Re: Comparing OLE Objects
ckulkarni - Wed Jul 18 06:58:38 EDT 2018

Mathias Mamsch - Wed Jul 18 03:12:45 EDT 2018

Well as far as I can see, the regexp in the code is listed as follows:

string picHeader = "{\\\\pict\\\\([^\\\\]+)(\\\\picw([^\\\\{}]+))?(\\\\pich([^\\\\]+))?\\\\picwgoal([-0-9]+)\\\\pichgoal([-0-9]+)" 
string picData = "([^}]+)"   

Your picture data is:

{\pict{\*\picprop}\wmetafile8\picw975\pich810\picwgoal975\pichgoal810
0100090000033a0700000200210600000000050000000b0200000000050000000c02350040001c
000000fb02f4ff000000000000900100000001000005005365676f65205549007659757c240aec ..... }

As described in the big fat red header, the regular expression needs to be changed, since DOORS has changed its RTF engine since then (or is using the Windows default one which has changed). In your case it does not seem to match the "\*\picprop" element, so it will parse only until \pict { and then then picData will parse the \*\picprop up to the last "}" ... So changing the regexp will work, however it is only a temporary solution. I still wait for somebody to step in, take for example the RTF Tokenizer I made here:

https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014923264&ps=25

and rewrite the OLE Parser to be able to handle any picture / OLE control words in the header and still be able to parse the OLE to the end. Because when you use a regexp, you always apply an order of the control words and any additional control word in the picture will break the parsing which is kind of bad. Maybe you are the one to rewrite the code to be more stable and post it back here? :-)

Regards, Mathias

Thank you Mathias,

 

I have one more doubt

There is a regexp given

string reResult = "({\\\\result([^}]+)})"  

 

What will be extracted with this expression?

I think it should extract the whole picture data as given below

{\result{\pict{\*\picprop}\wmetafile8\picw3840\pich300\picwgoal3840\pichgoal300
010009000003200000000000050000000000050000000b0200000000050000000c021102751a03
0000001e00030000001e000400000027010100030000000000..}

But this seems not working as when the same is extracted, the result is

val = s [match 6]            ; x->m_picture   = val

Result is: {\result{\pict{\*\picprop}

Regards,

Champa

 

 

Re: Comparing OLE Objects
Mathias Mamsch - Wed Jul 18 08:23:47 EDT 2018

ckulkarni - Wed Jul 18 06:58:38 EDT 2018

Thank you Mathias,

 

I have one more doubt

There is a regexp given

string reResult = "({\\\\result([^}]+)})"  

 

What will be extracted with this expression?

I think it should extract the whole picture data as given below

{\result{\pict{\*\picprop}\wmetafile8\picw3840\pich300\picwgoal3840\pichgoal300
010009000003200000000000050000000000050000000b0200000000050000000c021102751a03
0000001e00030000001e000400000027010100030000000000..}

But this seems not working as when the same is extracted, the result is

val = s [match 6]            ; x->m_picture   = val

Result is: {\result{\pict{\*\picprop}

Regards,

Champa

 

 

You are probably right. I am not sure how OLE objects looked, when I made the code, but I guess the unnecessary "{pictprop}" tag was not there, so you could get all picture data, by just parsing to the first closing brace } (instead of correctly parsing till the matching closing brace).  In any case, the code should probably be rewritten using a tokenizer. The regexps are too fragile. I am a bit disappointed, that nobody who used the OLE comparison code posted it back later after adapting the regexps but then again I never had the feeling with few exceptions that people were giving back to the community after receiving. Regards, Mathias

Re: Comparing OLE Objects
ckulkarni - Wed Sep 05 06:43:27 EDT 2018

Mathias Mamsch - Wed Feb 22 12:05:20 EST 2012

EDIT: 01/2015

The regular expressions in the Code need to be changed, since DOORS uses on modern platforms a different rich text component which will create a different OLE representation.

Until someone pressures me this change is left as an excercise for the reader.

 

Oh man, thats it, now I am releasing that stupid code as the giveaway of the day. That whole super secrecy thing of the DXL community sometimes really gives me the creeps. The reason why you are experiencing problems is explained here:

https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14448884&#14448884

And the solution to the problem is to compare the picture part of the OLE objects only, since the data part has 8-12 bytes changing randomly, when loading the module. The way to do this with the attached library is as about followed (an1 and an2 are the attribute names, but I guess you will figure that out).
 

OleObjects ol1 = createOleObjects (obj1.an1)
        OleObjects ol2 = createOleObjects (obj2.an2)
                
                // If this happens its bad: Then our regular expression in OleObjects.inc is wrong.
                if (null ol1 || null ol2) {
                        reportError("OLEERROR", "Cannot parse OLE Object in " (identifier obj1) "/" (identifier obj2) "\n")
                        return false
                }
                
                        // get the picture data of the first OLE object
                        Buffer pdi1 = picturedata ol1[0]
                        Buffer pdi2 = picturedata ol2[0]
 
                if (pdi1 == pdi2) print "Equal!"

 


You can additionally compare the length of the data part to detect invisible changes (if you are really interested in them). Obviously you still need to compare the non-richText part of the attribute and handle OLE object creation and deletion, but I guess this is straightforward. If you do comparison remember to implement a DOORS picture comparison too!

Regards, Mathias

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

Hello Mathias,

 

I am using the below function to get the rich text for OLE objects

string s = richTextWithOle(obj."Object Text")

But when I print the string s

I am unable to find the picture part.

Example

Usual format is

...

{\result{\pict{\*\picprop}\wmetafile8\picw3840\pich300\picwgoal3840\pichgoal300
010009000003200000000000050000000000050000000b0200000000050000000c021102751a03
0000001e00030000001e000400000027010100030000000000
}}}

But i am getting

..{\result{\pict{\*\picprop}\wmetafile8\picw3840\pich300\picwgoal3840\pichgoal300}}}

The Red color data is missing.

 

Earlier I used to get the usual format. But recently i am getting the data with missing picture part data(only meta data is displayed)

Can you please help me regarding this?

Re: Comparing OLE Objects
Mathias Mamsch - Sat Sep 08 04:51:12 EDT 2018

ckulkarni - Wed Sep 05 06:43:27 EDT 2018

Hello Mathias,

 

I am using the below function to get the rich text for OLE objects

string s = richTextWithOle(obj."Object Text")

But when I print the string s

I am unable to find the picture part.

Example

Usual format is

...

{\result{\pict{\*\picprop}\wmetafile8\picw3840\pich300\picwgoal3840\pichgoal300
010009000003200000000000050000000000050000000b0200000000050000000c021102751a03
0000001e00030000001e000400000027010100030000000000
}}}

But i am getting

..{\result{\pict{\*\picprop}\wmetafile8\picw3840\pich300\picwgoal3840\pichgoal300}}}

The Red color data is missing.

 

Earlier I used to get the usual format. But recently i am getting the data with missing picture part data(only meta data is displayed)

Can you please help me regarding this?

Are you saying you are seeing a picture, but if you print the richtext you do not see the picture data?

Only two ideas here:

- You are looking at the wrong attribute (verify that you really see a picture in Object Text)

- The picture is corrupt, whatever you seeing might be a DOORS Image

- or the DOORS client is able to show the picture but not to parse the information from the OLE

In any way - if you can not see the richtext there is probably nothing you can do. In any case you need to verify, if this is the case for each and every OLE object or if this is specific only to one object or module.

Regards, Mathias