OSDN Git Service

Fix an issue where items with different case are not displayed correctly in the folde...
[winmerge-jp/winmerge-jp.git] / Src / ConflictFileParser.cpp
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** 
3  * @file  ConflictFileParser.cpp
4  *
5  * @brief Implementation for conflict file parser.
6  */
7
8 // Conflict file parsing method modified from original code got from:
9 // TortoiseCVS - a Windows shell extension for easy version control
10 // Copyright (C) 2000 - Francis Irving
11 // <francis@flourish.org> - January 2001
12
13 #include "pch.h"
14 #include "ConflictFileParser.h"
15 #include "UnicodeString.h"
16 #include "UniFile.h"
17 #include "FileTextEncoding.h"
18 #include "codepage_detect.h"
19
20
21 // Note: keep these strings in "wrong" order so we can resolve this file :)
22 /** @brief String separating Mine and Theirs blocks. */
23 static const TCHAR Separator[] = _T("=======");
24 /** @brief String ending Theirs block (and conflict). */
25 static const TCHAR TheirsEnd[] = _T(">>>>>>> ");
26 /** @brief String starting Mine block (and conflict). */
27 static const TCHAR MineBegin[] = _T("<<<<<<< ");
28 /** @brief String starting Base block (and conflict). */
29 static const TCHAR BaseBegin[] = _T("||||||| ");
30
31 namespace ConflictFileParser
32 {
33
34 /**
35  * @brief Check if the file is a conflict file.
36  * This function checks if the conflict file marker is found from given file.
37  * This is faster than trying to parse a file that is not conflict file.
38  * @param [in] conflictFileName Full path to file to check.
39  * @return true if given file is a conflict file, false otherwise.
40  */
41 bool IsConflictFile(const String& conflictFileName)
42 {
43         UniMemFile conflictFile;
44         bool startFound = false;
45
46         // open input file
47         bool success = conflictFile.OpenReadOnly(conflictFileName);
48         if (!success)
49                 return false;
50
51         // Search for a conflict marker
52         bool linesToRead = true;
53         while (linesToRead && !startFound)
54         {
55                 String line;
56                 bool lossy;
57                 String eol;
58                 linesToRead = conflictFile.ReadString(line, eol, &lossy);
59
60                 std::string::size_type pos;
61                 pos = line.find(MineBegin);
62                 if (pos == 0)
63                         startFound = true;
64         }
65         conflictFile.Close();
66
67         return startFound;
68 }
69
70 /**
71  * @brief Parse a conflict file to separate files.
72  * This function parses a conflict file to two different files which can be
73  * opened into WinMerge's file compare.
74  * @param [in] conflictFileName Full path to conflict file.
75  * @param [in] workingCopyFileName Full path for user's modified file in
76  *  working copy/working folder.
77  * @param [in] newRevisionFileName Full path for revision control file.
78  * @param [in] iGuessEncodingType Try to guess codepage (not just unicode encoding)
79  * @param [out] bNestedConflicts returned as true if nested conflicts found.
80  * @return true if conflict file was successfully parsed, false otherwise.
81  */
82 bool ParseConflictFile(const String& conflictFileName,
83                 const String& workingCopyFileName, const String& newRevisionFileName, const String& baseRevisionFileName,
84                 int iGuessEncodingType, bool &bNestedConflicts, bool &b3way)
85 {
86         UniMemFile conflictFile;
87         UniStdioFile workingCopy;
88         UniStdioFile newRevision;
89         UniStdioFile baseRevision;
90         String line;
91         std::string::size_type pos;
92         int state;
93         int iNestingLevel = 0;
94         bool bResult = false;
95         String revision = _T("none");
96         bNestedConflicts = false;
97         b3way = false;
98
99         // open input file
100         bool success = conflictFile.OpenReadOnly(conflictFileName);
101
102         // Create output files
103         bool success2 = workingCopy.Open(workingCopyFileName, _T("wb"));
104         bool success3 = newRevision.Open(newRevisionFileName, _T("wb"));
105         bool success4 = baseRevision.Open(baseRevisionFileName, _T("wb"));
106
107         // detect codepage of conflict file
108         FileTextEncoding encoding = codepage_detect::Guess(conflictFileName, iGuessEncodingType);
109
110         conflictFile.SetUnicoding(encoding.m_unicoding);
111         conflictFile.SetBom(encoding.m_bom);
112         conflictFile.SetCodepage(encoding.m_codepage);
113         workingCopy.SetUnicoding(encoding.m_unicoding);
114         workingCopy.SetBom(encoding.m_bom);
115         workingCopy.SetCodepage(encoding.m_codepage);
116         newRevision.SetUnicoding(encoding.m_unicoding);
117         newRevision.SetBom(encoding.m_bom);
118         newRevision.SetCodepage(encoding.m_codepage);
119         baseRevision.SetUnicoding(encoding.m_unicoding);
120         baseRevision.SetBom(encoding.m_bom);
121         baseRevision.SetCodepage(encoding.m_codepage);
122
123         state = 0;
124         bool linesToRead = true;
125         do
126         {
127                 bool lossy;
128                 String eol;
129                 linesToRead = conflictFile.ReadString(line, eol, &lossy);
130                 switch (state)
131                 {
132                         // in common section
133                 case 0:
134                         // search beginning of conflict section
135                         pos = line.find(MineBegin);
136                         if (pos == 0)
137                         {
138                                 // working copy section starts
139                                 state = 1;
140                                 bResult = true;
141                         }
142                         else
143                         {
144                                 // we're in the common section, so write to both files
145                                 newRevision.WriteString(line);
146                                 newRevision.WriteString(eol);
147
148                                 baseRevision.WriteString(line);
149                                 baseRevision.WriteString(eol);
150
151                                 workingCopy.WriteString(line);
152                                 workingCopy.WriteString(eol);
153                         }
154                         break;
155
156                         // in working copy section
157                 case 1:
158                         // search beginning of conflict section
159                         pos = line.find(MineBegin);
160                         if (pos == 0)
161                         {
162                                 // nested conflict section starts
163                                 state = 3;
164                                 workingCopy.WriteString(line);
165                                 workingCopy.WriteString(eol);
166                         }
167                         else
168                         {
169                                 pos = line.find(BaseBegin);
170                                 if (pos != std::string::npos)
171                                 {
172                                         line = line.substr(0, pos);
173                                         if (!line.empty())
174                                         {
175                                                 baseRevision.WriteString(line);
176                                                 baseRevision.WriteString(eol);
177                                         }
178
179                                         // base revision section
180                                         state = 5;
181                                         b3way = true;
182                                 }
183                                 else
184                                 {
185                                         pos = line.find(Separator);
186                                         if ((pos != std::string::npos) && (pos == (line.length() - 7)))
187                                         {
188                                                 line = line.substr(0, pos);
189                                                 if (!line.empty())
190                                                 {
191                                                         workingCopy.WriteString(line);
192                                                         workingCopy.WriteString(eol);
193                                                 }
194
195                                                 //  new revision section
196                                                 state = 2;
197                                         }
198                                         else
199                                         {
200                                                 workingCopy.WriteString(line);
201                                                 workingCopy.WriteString(eol);
202                                         }
203                                 }
204                         }
205                         break;
206
207                         // in new revision section
208                 case 2:
209                         // search beginning of nested conflict section
210                         pos = line.find(MineBegin);
211                         if (pos == 0)
212                         {
213                                 // nested conflict section starts
214                                 state = 4;
215                                 newRevision.WriteString(line);
216                                 newRevision.WriteString(eol);
217                         }
218                         else
219                         {
220                                 pos = line.find(TheirsEnd);
221                                 if (pos != std::string::npos)
222                                 {
223                                         revision = line.substr(pos + 8);
224                                         line = line.substr(0, pos);
225                                         if (!line.empty())
226                                         {
227                                                 newRevision.WriteString(line);
228                                                 newRevision.WriteString(eol);
229                                         }
230
231                                         //  common section
232                                         state = 0;
233                                 }
234                                 else
235                                 {
236                                         newRevision.WriteString(line);
237                                         newRevision.WriteString(eol);
238                                 }
239                         }
240                         break;
241
242
243                         // in nested section in working copy section
244                 case 3:
245                         // search beginning of nested conflict section
246                         bNestedConflicts = true;
247                         pos = line.find(MineBegin);
248                         if (pos == 0)
249                         {
250                                 iNestingLevel++;
251                         }
252                         else
253                         {
254                                 pos = line.find(TheirsEnd);
255                                 if (pos != std::string::npos)
256                                 {
257                                         if (iNestingLevel == 0)
258                                         {
259                                                 state = 1;
260                                         }
261                                         else
262                                         {
263                                                 iNestingLevel--;
264                                         }
265                                 }
266                         }
267                         workingCopy.WriteString(line);
268                         workingCopy.WriteString(eol);
269                         break;
270
271                         // in nested section in new revision section
272                 case 4:
273                         // search beginning of nested conflict section
274                         pos = line.find(MineBegin);
275                         if (pos == 0)
276                         {
277                                 iNestingLevel++;
278                         }
279                         else
280                         {
281                                 pos = line.find(TheirsEnd);
282                                 if (pos != std::string::npos)
283                                 {
284                                         if (iNestingLevel == 0)
285                                         {
286                                                 state = 2;
287                                         }
288                                         else
289                                         {
290                                                 iNestingLevel--;
291                                         }
292                                 }
293                         }
294                         newRevision.WriteString(line);
295                         newRevision.WriteString(eol);
296                         break;
297
298                         // in base revision section
299                 case 5:
300                         pos = line.find(Separator);
301                         if ((pos != std::string::npos) && (pos == (line.length() - 7)))
302                         {
303                                 line = line.substr(0, pos);
304                                 if (!line.empty())
305                                 {
306                                         baseRevision.WriteString(line);
307                                         baseRevision.WriteString(eol);
308                                 }
309
310                                 //  new revision section
311                                 state = 2;
312                         }
313                         else
314                         {
315                                 baseRevision.WriteString(line);
316                                 baseRevision.WriteString(eol);
317                         }
318                         break;
319
320                 }
321         } while (linesToRead);
322
323         // Close
324         baseRevision.Close();
325         newRevision.Close();
326         workingCopy.Close();
327         conflictFile.Close();
328         return bResult;
329 }
330
331 }