Page 1 of 1

PB File Compare

Posted: Wed Jul 25, 2007 11:27 am
by peterb
My simple tool for visual file comparison.

Enjoy,

peterb



Image

Code: Select all

;- Author   : Petr Vavrin (peterb) 
;- Location : Czech Republic 
;- Email     : pb.pb@centrum.cz

Enumeration
  #window
  #compare_list
  #file1
  #file2
  #Compare
  #InputFile1
  #InputFile2
  #BrowseInputFile1
  #BrowseInputFile2
EndEnumeration

Structure compare
  original.s
  trimmed.s
  md5.s
  line.l
  line_len.l
  line_p.l
  shift.l
EndStructure

Macro IIf (expr, truepart, falsepart)
  If expr : truepart : Else : falsepart : EndIf
EndMacro

Procedure max ( value1.l, value2.l )
  IIf ( value2 > value1, max.l = value2, max.l = value1 )
  ProcedureReturn max
EndProcedure
  
Structure index
  line_length.l
  line_number.l
EndStructure  
  
Procedure CompareData ( file1.s, file2.s )

  ClearGadgetItemList ( #compare_list )

  NewList array1.compare()
  NewList array2.compare()
  NewList array1_index.index()
  NewList array2_index.index()
  
  Dim array2_line_len_min.l( 4096 )
  Dim array2_line_len_max.l( 4096 )
  
  Dim tmp.l( 65535 )
  
  For c = 0 To 4096
    array2_line_len_min( c ) = -1
    array2_line_len_max( c ) = -1
  Next
  
  c = 0
  If FileSize ( file1 )
    If OpenFile ( #file1, file1 )
      Repeat
        line.s      = ReadString ( #file1 )
        line_trim.s = Trim ( line )
        line_len.l  = Len  ( line_trim )
        AddElement ( array1() )
        array1()\original = line
        array1()\trimmed  = line_trim
        array1()\md5      = MD5Fingerprint ( @line_trim, line_len )
        array1()\line     = c
        array1()\line_len = line_len
        array1()\line_p   = -1
        array1()\shift    = 0
        c + 1
      Until Eof ( #file1 ) 
      CloseFile ( #file1 )
    EndIf
  EndIf

  c = 0
  If FileSize ( file2 )
    If OpenFile ( #file2, file2 )
      Repeat
        line.s      = ReadString ( #file2 )
        line_trim.s = Trim ( line )
        line_len.l  = Len  ( line_trim )
        AddElement ( array2() )
        array2()\original = line
        array2()\trimmed  = line_trim
        array2()\md5      = MD5Fingerprint ( @line_trim, line_len )
        array2()\line     = c
        array2()\line_len = line_len
        array2()\line_p   = -1
        array2()\shift    = 0

        AddElement ( array2_index() )
        array2_index()\line_length = line_len
        array2_index()\line_number = c

        c + 1
      Until Eof ( #file2 ) 
      CloseFile ( #file2 )
    EndIf
  EndIf
 
  SortStructuredList ( array2_index(), 0, OffsetOf ( index\line_length ), #PB_Sort_Long )

  c = 0
  ResetList ( array2_index() )
  While NextElement ( array2_index() )

    line_length.l = array2_index()\line_length

    If array2_line_len_min( line_length ) = -1
      array2_line_len_min( line_length ) = c
    EndIf

    array2_line_len_max( line_length ) = c
    c + 1
  Wend

  For c = 0 To 4096
    If array2_line_len_min( c ) > -1
      first = array2_line_len_min( c )
      last  = array2_line_len_max( c )

      ReDim tmp( last - first )
      x = 0
      For i = first To last
        SelectElement ( array2_index(), i)
        tmp( x ) = array2_index()\line_number
        x + 1
      Next
      
      SortArray ( tmp(), 0 )

      x = 0
      For i = first To last
        SelectElement ( array2_index(), i )
        array2_index()\line_number = tmp( x )
        x + 1
      Next
     
    EndIf
  Next      
        
  array1_count = CountList ( array1() )
  array2_count = CountList ( array2() )

  If array1_count > 0 And array2_count > 0
  
    p1      = 0
    p2_last = 0

    While p1 <= array1_count
      SelectElement( array1(), p1 )
      array1_line_length = array1()\line_len

      If array2_line_len_min( array1_line_length ) > -1

        For p2 = array2_line_len_min( array1_line_length ) To array2_line_len_max( array1_line_length )

          SelectElement ( array2_index(), p2 )
          
          If array2_index()\line_number >= p2_last
          
            SelectElement ( array2(), array2_index()\line_number )
            If array1()\md5 = array2()\md5 And Not array1()\trimmed = ""

              If array1()\line_p = -1 : array1()\line_p = array2_index()\line_number : EndIf
              If array2()\line_p = -1 : array2()\line_p = p1 : EndIf

              p2_last = array2_index()\line_number
              array2_line_len_min( array1_line_length ) = p2 + 1
              Break
            EndIf
          EndIf       
        Next
      EndIf
    
      p1 + 1
    Wend
 
    c.l      = 0
    shift1.l = 0
    shift2.l = 0
  
    While c < max ( CountList ( array1() ), CountList ( array2() ) )
  
      next_ = #True
  
      If c < CountList ( array2() )
        SelectElement ( array2(), c )
        If array2()\line_p > -1
  
          If ( array2()\line_p > c And array2()\line > -1 ) Or ( array2()\line_p + shift1 > c And array2()\line_p > -1 )
            shift2 + 1
            InsertElement ( array2() )
            array2()\line   = -1
            array2()\line_p = -1
            array2()\shift  = shift2
            next_ = #False
          EndIf
        EndIf
      EndIf
  
      If c < CountList ( array1() )
        SelectElement ( array1(), c )
        If array1()\line_p > -1
  
          If ( array1()\line_p > c And array1()\line > -1 ) Or ( array1()\line_p + shift2 > c And array1()\line_p > -1 )
            shift1 + 1
            InsertElement ( array1() )
            array1()\line   = -1
            array1()\line_p = -1
            array1()\shift  = shift1
            next_           = #False
          EndIf
        EndIf
      EndIf
  
      If next_
        c + 1
      EndIf
    Wend
    
    While CountList ( array1() ) < CountList ( array2() )
      AddElement ( array1() )
      array1()\line     = -1
      array1()\line_p   = -1
    Wend
    
    While CountList ( array2() ) < CountList ( array1() )
      AddElement ( array2() )
      array2()\line     = -1
      array2()\line_p   = -1
    Wend
  
    ResetList ( array1() )
    ResetList ( array2() )
    ln = 0
    While NextElement ( array1() )
      NextElement ( array2() )
      
      ln + 1
      IIf ( array1()\line > -1,   line1.s = Str ( array1()\line + 1 ),   line1.s = "" )
      IIf ( array2()\line > -1,   line2.s = Str ( array2()\line + 1 ),   line2.s = "" )
  
      If array1()\line_p > -1 And array1()\line_p = array2()\line
        color   = RGB ( 255, 255, 255 ) : state.s = "="
    
      ElseIf array2()\line > -1 And array1()\line = -1
        color   = RGB ( 151, 207, 255 ) : state.s = ">"
      
      ElseIf array1()\line > -1 And array2()\line = -1
        color   = RGB ( 249, 178, 178 ) : state.s = "<"
        
      ElseIf array1()\trimmed = array2()\trimmed
        color   = RGB ( 255, 255, 255 ) : state.s = "="
        
      Else
        color   = RGB ( 172, 251, 133 ) : state.s = "!"
      EndIf
     
      AddGadgetItem( #compare_list, ln - 1, Str(ln) + Chr(10) + line1 + Chr(10) + array1()\original + Chr(10) + state + Chr(10) + line2 + Chr(10) + array2()\original  )
      SetGadgetItemColor(#compare_list, ln - 1, #PB_Gadget_BackColor, color)
      SetGadgetItemColor(#compare_list, ln - 1, #PB_Gadget_BackColor, RGB ( 200, 200, 200 ), 0)
      SetGadgetItemColor(#compare_list, ln - 1, #PB_Gadget_BackColor, RGB ( 220, 220, 220 ), 1)
      SetGadgetItemColor(#compare_list, ln - 1, #PB_Gadget_BackColor, RGB ( 255, 220, 0 ), 3)
      SetGadgetItemColor(#compare_list, ln - 1, #PB_Gadget_BackColor, RGB ( 220, 220, 220 ), 4)
     
    Wend
  EndIf
  
EndProcedure

Procedure AlignColumn ( gadget, column, align)
  gadget_id = GadgetID ( gadget ) 
  liColumn.LV_COLUMN 
  liColumn\mask = #LVCF_FMT 
  liColumn\fmt  = align 
  SendMessage_ ( gadget_id, #LVM_SETCOLUMN, column, liColumn ) 
EndProcedure 

If OpenWindow ( #window, 0, 0, 800, 600, "PB File Compare", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered ) And CreateGadgetList ( WindowID ( #window ) ) 

  TextGadget      ( #PB_Any,             15, 15, 60, 20, "Input File 1:") 
  TextGadget      ( #PB_Any,             15, 40, 60, 20, "Input File 2:")

  StringGadget    ( #InputFile1,         80, 10, 435, 20, "", #WS_EX_STATICEDGE | #WS_BORDER) 
  StringGadget    ( #InputFile2,         80, 35, 435, 20, "", #WS_EX_STATICEDGE | #WS_BORDER)
        
  ButtonGadget    ( #BrowseInputFile1,  520, 10, 80, 20, "Browse", #BS_FLAT )
  ButtonGadget    ( #BrowseInputFile2,  520, 35, 80, 20, "Browse", #BS_FLAT )

  ButtonGadget    ( #Compare,           620, 10, 160, 45, "Compare", #BS_FLAT )

  ListIconGadget  ( #compare_list, 15,  70, WindowWidth( #window ) - 30, WindowHeight( #window ) - 90, "line", 50, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect | #ES_MULTILINE )
  AddGadgetColumn ( #compare_list, 1, "line 1", 50)
  AddGadgetColumn ( #compare_list, 2, "content 1", 270)
  AddGadgetColumn ( #compare_list, 3, "", 30)
  AddGadgetColumn ( #compare_list, 4, "line 2", 50)
  AddGadgetColumn ( #compare_list, 5, "content 2", 270)
  
  AlignColumn     ( #compare_list, 0, #LVCFMT_RIGHT)  ; #LVCFMT_LEFT | #LVCFMT_CENTER | #LVCFMT_RIGHT
  AlignColumn     ( #compare_list, 1, #LVCFMT_RIGHT)  ; #LVCFMT_LEFT | #LVCFMT_CENTER | #LVCFMT_RIGHT
  AlignColumn     ( #compare_list, 3, #LVCFMT_CENTER) ; #LVCFMT_LEFT | #LVCFMT_CENTER | #LVCFMT_RIGHT
  AlignColumn     ( #compare_list, 4, #LVCFMT_RIGHT)  ; #LVCFMT_LEFT | #LVCFMT_CENTER | #LVCFMT_RIGHT
 
  SetGadgetColor  ( #compare_list, #PB_Gadget_LineColor, RGB ( 225, 225, 225 ) )

  Repeat
    Event = WaitWindowEvent()
          
    If Event = #PB_Event_Gadget
          
      Select EventGadget()
        Case #Compare
          file1.s = GetGadgetText ( #InputFile1 )
          file2.s = GetGadgetText ( #InputFile2 )
          
          If FileSize ( file1 ) > 0
            SetGadgetColor  ( #InputFile1, #PB_Gadget_BackColor, RGB ( 255, 255, 255 ) )
            file1_state = #True
          Else
            SetGadgetColor  ( #InputFile1, #PB_Gadget_BackColor, RGB ( 255, 200, 200 ) )
            file1_state = #False
          EndIf
          
          If FileSize ( file2 ) > 0
            SetGadgetColor  ( #InputFile2, #PB_Gadget_BackColor, RGB ( 255, 255, 255 ) )
            file2_state = #True
          Else
            SetGadgetColor  ( #InputFile2, #PB_Gadget_BackColor, RGB ( 255, 200, 200 ) )
            file2_state = #False
          EndIf          
          
          If file1_state And file2_state
            CompareData ( file1, file2 )
          EndIf
          
        Case #BrowseInputFile1
          last_path.s = GetPathPart ( GetGadgetText ( #InputFile1 ) )
          IIf ( last_path <> "", StandardFile$ = last_path, StandardFile$ = "C:\" )
          File$ = OpenFileRequester ( "Please choose file #1 to load", StandardFile$, "(*.*)", 0 )
          If File$
            SetGadgetText ( #InputFile1, File$ )
          EndIf

        Case #BrowseInputFile2
          last_path.s = GetPathPart ( GetGadgetText ( #InputFile2 ) )
          IIf ( last_path <> "", StandardFile$ = last_path, StandardFile$ = "C:\" )
          File$ = OpenFileRequester ( "Please choose file #2 to load", StandardFile$, "(*.*)", 0 )
          If File$
            SetGadgetText ( #InputFile2, File$ )
          EndIf
      EndSelect
    EndIf
  Until Event = #PB_Event_CloseWindow
EndIf
End

Re: PB File Compare

Posted: Wed Jul 25, 2007 1:11 pm
by Kiffi
Great! Thanks for sharing!

Greetings ... Kiffi

Posted: Wed Jul 25, 2007 6:20 pm
by Fred
Looks good !

Posted: Wed Jul 25, 2007 6:54 pm
by Leonhard
Good work!

It is a little bit buggig.

Posted: Thu Jul 26, 2007 11:39 am
by dige
Great!

Please add two commands after line 314:

Code: Select all

  SetGadgetText ( #InputFile1, ProgramParameter() )
  SetGadgetText ( #InputFile2, ProgramParameter() )

Posted: Thu Jul 26, 2007 12:19 pm
by Kiffi
Leonhard wrote:It is a little bit buggig.
:roll:

please post the buggy code to give peterb the chance to fix it.

Greetings ... Kiffi

Posted: Thu Jul 26, 2007 12:21 pm
by Kaeru Gaman
at least he should say what the code does he calles "buggig"...

Posted: Fri Jul 27, 2007 5:23 am
by Leonhard
Kiffi wrote:please post the buggy code to give peterb the chance to fix it.
You have post!

Posted: Fri Aug 24, 2007 11:28 am
by GG
Nice Job !

Is it possible to add the possibility to compare a directory or multiple files ?