OSDN Git Service

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