OSDN Git Service

Fix the problem that when comparing with the BinaryContents compare method, the conte...
[winmerge-jp/winmerge-jp.git] / Src / CompareEngines / BinaryCompare.cpp
1 /**
2  * @file  BinaryCompare.cpp
3  *
4  * @brief Implementation file for BinaryCompare
5  */
6
7 #include "pch.h"
8 #include "BinaryCompare.h"
9 #include "DiffItem.h"
10 #include "PathContext.h"
11 #include "IAbortable.h"
12 #include "cio.h"
13
14 namespace CompareEngines
15 {
16
17 BinaryCompare::BinaryCompare() : m_piAbortable(nullptr)
18 {
19 }
20
21 BinaryCompare::~BinaryCompare() = default;
22
23 /**
24  * @brief Set Abortable-interface.
25  * @param [in] piAbortable Pointer to abortable interface.
26  */
27 void BinaryCompare::SetAbortable(const IAbortable * piAbortable)
28 {
29         m_piAbortable = const_cast<IAbortable*>(piAbortable);
30 }
31
32 static int compare_files(const String& file1, const String& file2, IAbortable *piAbortable)
33 {
34         const size_t bufsize = 1024 * 256;
35         int code;
36         int fd1 = -1, fd2 = -1;
37         
38         cio::tsopen_s(&fd1, file1, O_BINARY | O_RDONLY, _SH_DENYNO, _S_IREAD);
39         cio::tsopen_s(&fd2, file2, O_BINARY | O_RDONLY, _SH_DENYNO, _S_IREAD);
40         if (fd1 != -1 && fd2 != -1)
41         {
42                 for (;;)
43                 {
44                         if (piAbortable && piAbortable->ShouldAbort())
45                         {
46                                 code = DIFFCODE::CMPABORT;
47                                 break;
48                         }
49                         char buf1[bufsize];
50                         char buf2[bufsize];
51                         int size1 = cio::read_i(fd1, buf1, sizeof(buf1));
52                         int size2 = cio::read_i(fd2, buf2, sizeof(buf2));
53                         if (size1 <= 0 || size2 <= 0)
54                         {
55                                 if (size1 < 0 || size2 < 0)
56                                         code = DIFFCODE::CMPERR;
57                                 else if (size1 == size2)
58                                         code = DIFFCODE::SAME;
59                                 else
60                                         code = DIFFCODE::DIFF;
61                                 break;
62                         }
63                         if (size1 != size2 || memcmp(buf1, buf2, size1) != 0)
64                         {
65                                 code = DIFFCODE::DIFF;
66                                 break;
67                         }
68                 }
69         }
70         else
71         {
72                 code = DIFFCODE::CMPERR;
73         }
74         if (fd1 != -1)
75                 cio::close(fd1);
76         if (fd2 != -1)
77                 cio::close(fd2);
78
79         return code;
80 }
81
82 /**
83  * @brief Compare two specified files, byte-by-byte
84  * @param [in] di Diffitem info.
85  * @return DIFFCODE
86  */
87 int BinaryCompare::CompareFiles(const PathContext& files, const DIFFITEM &di) const
88 {
89         switch (files.GetSize())
90         {
91         case 2:
92                 // If the file size is 0, don't immediately assume that there is a difference even if the files have different sizes, because of possible symlinks.
93                 return (di.diffFileInfo[0].size != di.diffFileInfo[1].size && 
94                             di.diffFileInfo[0].size != 0 && di.diffFileInfo[1].size != 0) ? 
95                         DIFFCODE::DIFF : compare_files(files[0], files[1], m_piAbortable);
96         case 3:
97                 unsigned code10 = (di.diffFileInfo[1].size != di.diffFileInfo[0].size &&
98                                        di.diffFileInfo[1].size != 0 && di.diffFileInfo[0].size != 0) ?
99                         DIFFCODE::DIFF : compare_files(files[1], files[0], m_piAbortable);
100                 unsigned code12 = (di.diffFileInfo[1].size != di.diffFileInfo[2].size &&
101                                        di.diffFileInfo[1].size != 0 && di.diffFileInfo[2].size != 0) ?
102                         DIFFCODE::DIFF : compare_files(files[1], files[2], m_piAbortable);
103                 unsigned code02 = DIFFCODE::SAME;
104                 if (code10 == DIFFCODE::SAME && code12 == DIFFCODE::SAME)
105                         return DIFFCODE::SAME;
106                 else if (code10 == DIFFCODE::SAME && code12 == DIFFCODE::DIFF)
107                         return DIFFCODE::DIFF | DIFFCODE::DIFF3RDONLY;
108                 else if (code10 == DIFFCODE::DIFF && code12 == DIFFCODE::SAME)
109                         return DIFFCODE::DIFF | DIFFCODE::DIFF1STONLY;
110                 else if (code10 == DIFFCODE::DIFF && code12 == DIFFCODE::DIFF)
111                 {
112                         code02 = (di.diffFileInfo[0].size != di.diffFileInfo[2].size && 
113                                   di.diffFileInfo[0].size != 0 && di.diffFileInfo[2].size != 0) ?
114                                 DIFFCODE::DIFF : compare_files(files[0], files[2], m_piAbortable);
115                         if (code02 == DIFFCODE::SAME)
116                                 return DIFFCODE::DIFF | DIFFCODE::DIFF2NDONLY;
117                 }
118                 if (code10 == DIFFCODE::CMPERR || code12 == DIFFCODE::CMPERR || code02 == DIFFCODE::CMPERR)
119                         return DIFFCODE::CMPERR;
120                 return DIFFCODE::DIFF;
121         }
122         return DIFFCODE::CMPERR;
123 }
124
125 } // namespace CompareEngines