Topic
  • 28 replies
  • Latest Post - ‏2015-02-09T16:42:26Z by Mathias Mamsch
MarkN_HS
MarkN_HS
1 Post

Pinned topic Comparing OLE Objects

‏2010-05-05T19:55:42Z |
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
Updated on 2013-02-06T18:04:52Z at 2013-02-06T18:04:52Z by clhoover
  • doors36677
    doors36677
    92 Posts

    Re: Comparing OLE Objects

    ‏2010-05-06T11:05:21Z  
    Leave your email here and I will provide you with an approach forward.
  • aakhws
    aakhws
    2 Posts

    Re: Comparing OLE Objects

    ‏2010-05-07T03:01:40Z  
    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
  • SystemAdmin
    SystemAdmin
    3180 Posts

    Re: Comparing OLE Objects

    ‏2012-02-22T02:34:25Z  
    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
  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2012-02-22T17:05:20Z  
    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

     

    Updated on 2015-02-09T11:36:11Z at 2015-02-09T11:36:11Z by Mathias Mamsch
  • David_G_Bond
    David_G_Bond
    55 Posts

    Re: Comparing OLE Objects

    ‏2012-02-28T17:21:27Z  

    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).
     

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">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!" </pre>

     


    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
  • clhoover
    clhoover
    8 Posts

    Re: Comparing OLE Objects

    ‏2013-02-05T16:38:20Z  

    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).
     

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">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!" </pre>

     


    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?
  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2013-02-06T13:02:18Z  
    • clhoover
    • ‏2013-02-05T16:38:20Z
    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
  • clhoover
    clhoover
    8 Posts

    Re: Comparing OLE Objects

    ‏2013-02-06T18:04:52Z  
    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.
  • bungle_77
    bungle_77
    58 Posts

    Re: Comparing OLE Objects

    ‏2014-01-02T12:00:00Z  

    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).
     

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">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!" </pre>

     


    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 ?

    Updated on 2014-01-02T14:01:47Z at 2014-01-02T14:01:47Z by bungle_77
  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2014-01-02T17:43:22Z  
    • bungle_77
    • ‏2014-01-02T12:00:00Z

    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

  • bungle_77
    bungle_77
    58 Posts

    Re: Comparing OLE Objects

    ‏2014-01-03T09:37:44Z  

    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?

    Updated on 2014-01-03T09:53:46Z at 2014-01-03T09:53:46Z by bungle_77
  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2014-01-04T20:47:41Z  
    • bungle_77
    • ‏2014-01-03T09:37:44Z

    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

  • bungle_77
    bungle_77
    58 Posts

    Re: Comparing OLE Objects

    ‏2014-01-07T10:36:59Z  

    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):

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">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 </pre>

    Hope that helps, regards, Mathias

    thanks a lot Mathias, your post is really precious!

  • llandale
    llandale
    2972 Posts

    Re: Comparing OLE Objects

    ‏2014-01-07T21:24:55Z  
    • bungle_77
    • ‏2014-01-02T12:00:00Z

    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

  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2014-01-08T09:01:17Z  
    • llandale
    • ‏2014-01-07T21:24:55Z

    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

  • llandale
    llandale
    2972 Posts

    Re: Comparing OLE Objects

    ‏2014-01-08T16:50:39Z  

    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

  • dacapri
    dacapri
    11 Posts

    Re: Comparing OLE Objects

    ‏2014-01-28T08:34:51Z  

    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

  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2014-01-28T19:00:44Z  
    • dacapri
    • ‏2014-01-28T08:34:51Z

    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

  • dacapri
    dacapri
    11 Posts

    Re: Comparing OLE Objects

    ‏2014-01-30T08:05:37Z  

    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

  • bungle_77
    bungle_77
    58 Posts

    Re: Comparing OLE Objects

    ‏2014-02-03T15:14:40Z  

    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):

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">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 </pre>

    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

    Updated on 2014-02-03T15:34:03Z at 2014-02-03T15:34:03Z by bungle_77
  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2014-02-03T22:59:09Z  
    • bungle_77
    • ‏2014-02-03T15:14:40Z

    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

  • bungle_77
    bungle_77
    58 Posts

    Re: Comparing OLE Objects

    ‏2014-02-04T09:23:14Z  

    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:

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">set( o_Son."Object Text", o_Father."Object Text") </pre>

    if it also shows this behaviour.

    Regards, Mathias

    great it works fine.

    Thanks again

  • bungle_77
    bungle_77
    58 Posts

    Re: Comparing OLE Objects

    ‏2014-03-14T09:39:45Z  

    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:

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">set( o_Son."Object Text", o_Father."Object Text") </pre>

    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

  • EHcnck
    EHcnck
    78 Posts

    Re: Comparing OLE Objects

    ‏2015-02-03T16:27:17Z  
    • dacapri
    • ‏2014-01-30T08:05:37Z

    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?

     

  • Wolfgang Uhr
    Wolfgang Uhr
    247 Posts

    Re: Comparing OLE Objects

    ‏2015-02-05T07:02:26Z  
    • EHcnck
    • ‏2015-02-03T16:27:17Z

    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

  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2015-02-09T11:32:19Z  
    • EHcnck
    • ‏2015-02-03T16:27:17Z

    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

  • Wolfgang Uhr
    Wolfgang Uhr
    247 Posts

    Re: Comparing OLE Objects

    ‏2015-02-09T15:47:10Z  

    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).
     

    <pre class="javascript dw" data-editor-lang="js" data-pbcklang="javascript" dir="ltr">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!" </pre>

     


    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?

    Updated on 2015-02-10T07:14:58Z at 2015-02-10T07:14:58Z by Wolfgang Uhr
  • Mathias Mamsch
    Mathias Mamsch
    1969 Posts

    Re: Comparing OLE Objects

    ‏2015-02-09T16:42:26Z  

    > 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