OSDN Git Service

PATCH: [ 1435361 ] Fix and cleanup project file code
[winmerge-jp/winmerge-jp.git] / Src / ProjectFile.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    License (GPLv2+):
3 //    This program is free software; you can redistribute it and/or modify
4 //    it under the terms of the GNU General Public License as published by
5 //    the Free Software Foundation; either version 2 of the License, or (at
6 //    your option) any later version.
7 //    
8 //    This program is distributed in the hope that it will be useful, but
9 //    WITHOUT ANY WARRANTY; without even the implied warranty of
10 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //    GNU General Public License for more details.
12 //
13 //    You should have received a copy of the GNU General Public License
14 //    along with this program; if not, write to the Free Software
15 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 /////////////////////////////////////////////////////////////////////////////
17 /** 
18  * @file  ProjectFile.cpp
19  *
20  * @brief Implementation file for ProjectFile class
21  */
22 // RCS ID line follows -- this is updated by CVS
23 // $Id$
24
25 #include "stdafx.h"
26 #include "ProjectFile.h"
27 #include "markdown.h"
28
29 ProjectFile::ProjectFile()
30 {
31         m_subfolders = -1;
32 }
33
34 /** 
35  * @brief Get message from exception into sError, or else throw it.
36  *
37  * If caller provided the address of an error string (sError),
38  *  this populates the error string (if possible) and returns FALSE
39  *
40  * If caller did not provide the address of an error string (sError==NULL)
41  *  this rethrows the error
42  */
43 static BOOL NTAPI False(CException *e, CString *sError)
44 {
45         if (sError == NULL)
46                 throw e;
47         TCHAR szError[4096] = _T("");
48         e->GetErrorMessage(szError, sizeof(szError)/sizeof(szError[0]));
49         *sError = szError;
50         e->Delete();
51         return FALSE;
52 }
53
54 /** 
55  * @brief Open given path-file and read data from it to member variables.
56  *
57  * Errors are returned in sError, unless it is NULL, in which case they are thrown
58  */
59 BOOL ProjectFile::Read(LPCTSTR path, CString *sError)
60 {
61         try
62         {
63                 CMarkdown::EntityMap entities;
64                 entities.Load();
65                 CMarkdown::File xmlfile = path;
66                 if (xmlfile.pImage == NULL)
67                 {
68                         CFileException::ThrowOsError(GetLastError(), path);
69                 }
70                 // If encoding is other than UTF-8, assume CP_ACP
71                 CMarkdown::String encoding = CMarkdown(xmlfile).Move("?xml").GetAttribute("encoding");
72                 UINT codepage = lstrcmpiA(encoding.A, "UTF-8") == 0 ? CP_UTF8 : CP_ACP;
73
74                 CMarkdown project = CMarkdown(xmlfile).Move("project").Pop();
75                 CMarkdown paths = CMarkdown(project).Move("paths").Pop();
76                 m_leftFile = CMarkdown::String(CMarkdown(paths).Move("left").GetInnerText()->Unicode(codepage)->Resolve(entities)).W;
77                 m_rightFile = CMarkdown::String(CMarkdown(paths).Move("right").GetInnerText()->Unicode(codepage)->Resolve(entities)).W;
78                 m_filter = CMarkdown::String(CMarkdown(paths).Move("filter").GetInnerText()->Unicode(codepage)->Resolve(entities)).W;
79                 sscanf(CMarkdown::String(CMarkdown(paths).Move("subfolders").GetInnerText()).A, "%d", &m_subfolders);
80         }
81         catch (CException *e)
82         {
83                 return False(e, sError);
84         }
85         return TRUE;
86 }
87
88 /** 
89  * @brief Save data from member variables to path-file.
90  * @note paths are converted to UTF-8
91  */
92 BOOL ProjectFile::Save(LPCTSTR path, CString *sError)
93 {
94         try
95         {
96                 static const char szFormat[]
97                 (
98                         "<?xml version='1.0' encoding='UTF-8'?>\n"
99                         "<project>\n"
100                         "\t<paths>\n"
101                         "\t\t<left>%s</left>\n"
102                         "\t\t<right>%s</right>\n"
103                         "\t\t<filter>%s</filter>\n"
104                         "\t\t<subfolders>%d</subfolders>\n"
105                         "\t</paths>\n"
106                         "</project>\n"
107                 );
108                 fprintf
109                 (
110                         CStdioFile(path, CFile::modeCreate|CFile::modeWrite|CFile::typeText).m_pStream,
111                         szFormat,
112                         CMarkdown::String(CMarkdown::HSTR(GetLeft().AllocSysString())->Entities()->Octets(CP_UTF8)).A,
113                         CMarkdown::String(CMarkdown::HSTR(GetRight().AllocSysString())->Entities()->Octets(CP_UTF8)).A,
114                         CMarkdown::String(CMarkdown::HSTR(GetFilter().AllocSysString())->Entities()->Octets(CP_UTF8)).A,
115                         GetSubfolders() ? 1 : 0
116                 );
117         }
118         catch (CException *e)
119         {
120                 return False(e, sError);
121         }
122         return TRUE;
123 }
124
125 /** 
126  * @brief Returns if left path is defined.
127  */
128 BOOL ProjectFile::HasLeft() const
129 {
130         return !m_leftFile.IsEmpty();
131 }
132
133 /** 
134  * @brief Returns if right path is defined.
135  */
136 BOOL ProjectFile::HasRight() const
137 {
138         return !m_rightFile.IsEmpty();
139 }
140
141 /** 
142  * @brief Returns if filter is defined.
143  */
144 BOOL ProjectFile::HasFilter() const
145 {
146         return !m_filter.IsEmpty();
147 }
148
149 /** 
150  * @brief Returns if subfolder is included.
151  */
152 BOOL ProjectFile::HasSubfolders() const
153 {
154         return (m_subfolders != -1);
155 }
156
157 /** 
158  * @brief Returns left path.
159  */
160 CString ProjectFile::GetLeft() const
161 {
162         return m_leftFile;
163 }
164
165 /** 
166  * @brief Set left path, returns old left path.
167  */
168 CString ProjectFile::SetLeft(const CString& sLeft)
169 {
170         CString sLeftOld = GetLeft();
171         m_leftFile = sLeft;
172
173         return sLeftOld;
174 }
175
176 /** 
177  * @brief Returns right path.
178  */
179 CString ProjectFile::GetRight() const
180 {
181         return m_rightFile;
182 }
183
184 /** 
185  * @brief Set right path, returns old right path.
186  */
187 CString ProjectFile::SetRight(const CString& sRight)
188 {
189         CString sRightOld = GetRight();
190         m_rightFile = sRight;
191
192         return sRightOld;
193 }
194
195 /** 
196  * @brief Returns filter.
197  */
198 CString ProjectFile::GetFilter() const
199 {
200         return m_filter;
201 }
202
203 /** 
204  * @brief Set filter, returns old filter.
205  */
206 CString ProjectFile::SetFilter(const CString& sFilter)
207 {
208         CString sFilterOld = GetFilter();
209         m_filter = sFilter;
210
211         return sFilterOld;
212 }
213
214 /** 
215  * @brief Returns subfolder included -setting.
216  */
217 int ProjectFile::GetSubfolders() const
218 {
219         return m_subfolders;
220 }
221
222 /** 
223  * @brief set subfolder, returns old subfolder value.
224  */
225 int ProjectFile::SetSubfolders(const int iSubfolder)
226 {
227         int iSubfoldersOld = GetSubfolders(); 
228         m_subfolders = iSubfolder ? 1 : 0;
229
230         return iSubfoldersOld;
231 }
232
233 /** 
234  * @brief Reads one value from XML data.
235  */
236 BOOL ProjectFile::GetVal(TCHAR *pPaths, TCHAR *pVal, CString * sval,
237                 TCHAR *ptag1, TCHAR *ptag2, TCHAR *pbuf)
238 {
239         if (pPaths && pVal && pVal > pPaths)
240         {
241                 TCHAR tmpPath[MAX_PATH] = {0};
242                 TCHAR *pTagEnd = _tcsstr(pbuf, ptag2);
243                 if ((pTagEnd - pVal) < (MAX_PATH * sizeof(TCHAR)))
244                 {
245                         pVal += _tcslen(ptag1);
246                         _tcsncpy(tmpPath, pVal, pTagEnd - pVal);
247                         *sval = tmpPath;
248                         return TRUE;
249                 }
250         }
251         return FALSE;
252 }
253
254 /** 
255  * @brief Returns left and right paths and recursive from project file
256  * 
257  * @param [out] sLeft Left path
258  * @param [out] sRight Right path
259  * @param [out] bSubFolders If TRUE subfolders included (recursive compare)
260  */
261 void ProjectFile::GetPaths(CString & sLeft, CString & sRight,
262         BOOL & bSubfolders) const
263 {
264         if (HasLeft())
265                 sLeft = GetLeft();
266         if (HasRight())
267                 sRight = GetRight();
268         if (HasSubfolders())
269                 bSubfolders = (GetSubfolders() == 1);
270 }