OSDN Git Service

PATCH: [ 1590892 ] Handle unicode paths for project files
[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 <scew/scew.h>
27
28 #include "ProjectFile.h"
29
30 // Constants for xml element names
31 const TCHAR Root_element_name[] = _T("project");
32 const TCHAR Paths_element_name[] = _T("paths");
33 const TCHAR Left_element_name[] = _T("left");
34 const TCHAR Right_element_name[] = _T("right");
35 const TCHAR Filter_element_name[] = _T("filter");
36 const TCHAR Subfolders_element_name[] = _T("subfolders");
37 const TCHAR Left_ro_element_name[] = _T("left-readonly");
38 const TCHAR Right_ro_element_name[] = _T("right-readonly");
39
40 /** 
41  * @brief Standard constructor.
42  */
43  ProjectFile::ProjectFile()
44 : m_subfolders(-1)
45 , m_bLeftReadOnly(FALSE)
46 , m_bRightReadOnly(FALSE)
47 {
48 }
49
50 /** 
51  * @brief Open given path-file and read data from it to member variables.
52  * @param [in] path Path to project file.
53  * @param [out] sError Error string if error happened.
54  * @return TRUE if reading succeeded, FALSE if error happened.
55  */
56 BOOL ProjectFile::Read(LPCTSTR path, CString *sError)
57 {
58         BOOL loaded = FALSE;
59     scew_tree* tree = NULL;
60     scew_parser* parser = NULL;
61
62     parser = scew_parser_create();
63     scew_parser_ignore_whitespaces(parser, 1);
64
65         FILE * fp = _tfopen(path, _T("r"));
66         if (fp)
67         {
68                 if (scew_parser_load_file_fp(parser, fp))
69                 {
70                         tree = scew_parser_tree(parser);
71
72                         scew_element * root = GetRootElement(tree);
73                         if (root)
74                         {
75                                 loaded = TRUE;
76                                 GetPathsData(root);
77                         };
78                 }
79                 scew_tree_free(tree);
80
81                 /* Frees the SCEW parser */
82                 scew_parser_free(parser);
83                 fclose(fp);
84         }
85         return loaded;
86 }
87
88 /** 
89  * @brief Return project file XML's root element.
90  * @param [in] tree XML tree we got from the parser.
91  * @return Root element pointer.
92  */
93 scew_element* ProjectFile::GetRootElement(scew_tree * tree)
94 {
95         scew_element * root = NULL;
96
97         if (tree != NULL)
98         {
99                 root = scew_tree_root(tree);
100         }
101
102         if (root != NULL)
103         {
104                 // Make sure we have correct root element
105                 if (_tcscmp(Root_element_name, scew_element_name(root)) != 0)
106                 {
107                         root = NULL;
108                 }
109         }
110         return root;
111 }
112
113 /** 
114  * @brief Reads the paths data from the XML data.
115  * This function reads the paths data inside given element in XML data.
116  * @param [in] parent Parent element for the paths data.
117  */
118 void ProjectFile::GetPathsData(scew_element * parent)
119 {
120         scew_element *paths = NULL;
121
122         if (parent != NULL)
123         {
124                 paths = scew_element_by_name(parent, Paths_element_name);
125         }
126
127         if (paths != NULL)
128         {
129                 scew_element *left = NULL;
130                 scew_element *right = NULL;
131                 scew_element *filter = NULL;
132                 scew_element *subfolders = NULL;
133                 scew_element *left_ro = NULL;
134                 scew_element *right_ro = NULL;
135
136                 left = scew_element_by_name(paths, Left_element_name);
137                 right = scew_element_by_name(paths, Right_element_name);
138                 filter = scew_element_by_name(paths, Filter_element_name);
139                 subfolders = scew_element_by_name(paths, Subfolders_element_name);
140                 left_ro = scew_element_by_name(paths, Left_ro_element_name);
141                 right_ro = scew_element_by_name(paths, Right_ro_element_name);
142
143                 if (left)
144                 {
145                         LPCTSTR path = NULL;
146                         path = scew_element_contents(right);
147                         m_leftFile = path;
148                 }
149                 if (right)
150                 {
151                         LPCTSTR path = NULL;
152                         path = scew_element_contents(right);
153                         m_rightFile = path;
154                 }
155                 if (filter)
156                 {
157                         LPCTSTR filtername = NULL;
158                         filtername = scew_element_contents(filter);
159                         m_filter = filtername;
160                 }
161                 if (subfolders)
162                 {
163                         LPCTSTR folders = NULL;
164                         folders = scew_element_contents(subfolders);
165                         m_subfolders = _ttoi(folders);
166                 }
167                 if (left_ro)
168                 {
169                         LPCTSTR readonly = NULL;
170                         readonly = scew_element_contents(left_ro);
171                         m_bLeftReadOnly = (_ttoi(readonly) != 0);
172                 }
173                 if (right_ro)
174                 {
175                         LPCTSTR readonly = NULL;
176                         readonly = scew_element_contents(right_ro);
177                         m_bRightReadOnly = (_ttoi(readonly) != 0);
178                 }
179         }
180 }
181
182 /** 
183  * @brief Save data from member variables to path-file.
184  * @param [in] path Path to project file.
185  * @param [out] sError Error string if error happened.
186  * @return TRUE if saving succeeded, FALSE if error happened.
187  */
188 BOOL ProjectFile::Save(LPCTSTR path, CString *sError)
189 {
190         BOOL success = TRUE;
191         scew_tree* tree = NULL;
192         scew_element* root = NULL;
193         scew_element* paths = NULL;
194
195         tree = scew_tree_create();
196         root = scew_tree_add_root(tree, Root_element_name);
197         if (root != NULL)
198         {
199                 paths = AddPathsElement(root);
200         }
201         else
202                 success = FALSE;
203
204         if (paths != NULL)
205         {
206                 AddPathsContent(paths);
207         }
208         else
209                 success = FALSE;
210         
211         scew_tree_set_xml_encoding(tree, _T("UTF-8"));
212
213         // Set the XML file standalone
214         scew_tree_set_xml_standalone(tree, 1);
215
216         FILE * fp = _tfopen(path, _T("w"));
217         if (fp)
218         {
219                 if (!scew_writer_tree_fp(tree, fp))
220                 {
221                         success = FALSE;
222                         *sError = LoadResString(IDS_FILEWRITE_ERROR);
223                 }
224                 fclose(fp);
225         }
226         else
227         {
228                 success = FALSE;
229         }
230         
231         /* Frees the SCEW tree */
232         scew_tree_free(tree);
233
234         if (success == FALSE)
235         {
236                 *sError = LoadResString(IDS_FILEWRITE_ERROR);
237         }
238         return success;
239 }
240
241 /**
242  * @brief Add paths element into XML tree.
243  * @param [in] parent Parent element for the paths element.
244  * @return pointer to added paths element.
245  */
246 scew_element* ProjectFile::AddPathsElement(scew_element * parent)
247 {
248         scew_element* element = NULL;
249         element = scew_element_add(parent, Paths_element_name);
250         return element;
251 }
252
253 /**
254  * @brief Add paths data to the XML tree.
255  * This function adds our paths data to the XML tree.
256  * @param [in] parent Parent element for paths data.
257  * @return TRUE if we succeeded, FALSE otherwise.
258  */
259 BOOL ProjectFile::AddPathsContent(scew_element * parent)
260 {
261         scew_element* element = NULL;
262
263         if (!m_leftFile.IsEmpty())
264         {
265                 LPCTSTR path;
266                 element = scew_element_add(parent, Left_element_name);
267                 path = m_leftFile.GetBuffer(MAX_PATH);
268                 scew_element_set_contents(element, path);
269                 m_leftFile.ReleaseBuffer();
270         }
271
272         if (!m_rightFile.IsEmpty())
273         {
274                 LPCTSTR path;
275                 element = scew_element_add(parent, Right_element_name);
276                 path = m_rightFile.GetBuffer(MAX_PATH);
277                 scew_element_set_contents(element, path);
278                 m_rightFile.ReleaseBuffer();
279         }
280
281         if (!m_filter.IsEmpty())
282         {
283                 LPCTSTR filter;
284                 element = scew_element_add(parent, Filter_element_name);
285                 filter = m_filter.GetBuffer(MAX_PATH);
286                 scew_element_set_contents(element, filter);
287                 m_filter.ReleaseBuffer();
288         }
289
290         element = scew_element_add(parent, Subfolders_element_name);
291         if (m_subfolders != 0)
292                 scew_element_set_contents(element, _T("1"));
293         else
294                 scew_element_set_contents(element, _T("0"));
295
296         element = scew_element_add(parent, Left_ro_element_name);
297         if (m_bLeftReadOnly)
298                 scew_element_set_contents(element, _T("1"));
299         else
300                 scew_element_set_contents(element, _T("0"));
301
302         element = scew_element_add(parent, Right_ro_element_name);
303         if (m_bRightReadOnly)
304                 scew_element_set_contents(element, _T("1"));
305         else
306                 scew_element_set_contents(element, _T("0"));
307
308         return TRUE;
309 }
310
311 /** 
312  * @brief Returns if left path is defined.
313  */
314 BOOL ProjectFile::HasLeft() const
315 {
316         return !m_leftFile.IsEmpty();
317 }
318
319 /** 
320  * @brief Returns if right path is defined.
321  */
322 BOOL ProjectFile::HasRight() const
323 {
324         return !m_rightFile.IsEmpty();
325 }
326
327 /** 
328  * @brief Returns if filter is defined.
329  */
330 BOOL ProjectFile::HasFilter() const
331 {
332         return !m_filter.IsEmpty();
333 }
334
335 /** 
336  * @brief Returns if subfolder is included.
337  */
338 BOOL ProjectFile::HasSubfolders() const
339 {
340         return (m_subfolders != -1);
341 }
342
343 /** 
344  * @brief Returns left path.
345  * @param [out] pReadOnly TRUE if readonly was specified for path.
346  */
347 CString ProjectFile::GetLeft(BOOL * pReadOnly /*=NULL*/) const
348 {
349         if (pReadOnly)
350                 *pReadOnly = m_bLeftReadOnly;
351         return m_leftFile;
352 }
353
354 /** 
355  * @brief Returns if left path is specified read-only.
356  */
357 BOOL ProjectFile::GetLeftReadOnly() const
358 {
359         return m_bLeftReadOnly;
360 }
361
362 /** 
363  * @brief Set left path, returns old left path.
364  * @param [in] sLeft Left path.
365  * @param [in] bReadOnly Will path be recorded read-only?
366  */
367 CString ProjectFile::SetLeft(const CString& sLeft, const BOOL * pReadOnly /*=NULL*/)
368 {
369         CString sLeftOld = GetLeft();
370         m_leftFile = sLeft;
371         if (pReadOnly)
372                 m_bLeftReadOnly = *pReadOnly;
373
374         return sLeftOld;
375 }
376
377 /** 
378  * @brief Returns right path.
379  * @param [out] pReadOnly TRUE if readonly was specified for path.
380  */
381 CString ProjectFile::GetRight(BOOL * pReadOnly /*=NULL*/) const
382 {
383         if (pReadOnly)
384                 *pReadOnly = m_bRightReadOnly;
385         return m_rightFile;
386 }
387
388 /** 
389  * @brief Returns if right path is specified read-only.
390  */
391 BOOL ProjectFile::GetRightReadOnly() const
392 {
393         return m_bRightReadOnly;
394 }
395
396 /** 
397  * @brief Set right path, returns old right path.
398  * @param [in] sRight Right path.
399  * @param [in] bReadOnly Will path be recorded read-only?
400  */
401 CString ProjectFile::SetRight(const CString& sRight, const BOOL * pReadOnly /*=NULL*/)
402 {
403         CString sRightOld = GetRight();
404         m_rightFile = sRight;
405         if (pReadOnly)
406                 m_bRightReadOnly = *pReadOnly;
407
408         return sRightOld;
409 }
410
411 /** 
412  * @brief Returns filter.
413  */
414 CString ProjectFile::GetFilter() const
415 {
416         return m_filter;
417 }
418
419 /** 
420  * @brief Set filter, returns old filter.
421  */
422 CString ProjectFile::SetFilter(const CString& sFilter)
423 {
424         CString sFilterOld = GetFilter();
425         m_filter = sFilter;
426
427         return sFilterOld;
428 }
429
430 /** 
431  * @brief Returns subfolder included -setting.
432  */
433 int ProjectFile::GetSubfolders() const
434 {
435         return m_subfolders;
436 }
437
438 /** 
439  * @brief set subfolder, returns old subfolder value.
440  */
441 int ProjectFile::SetSubfolders(const int iSubfolder)
442 {
443         int iSubfoldersOld = GetSubfolders(); 
444         m_subfolders = iSubfolder ? 1 : 0;
445
446         return iSubfoldersOld;
447 }
448
449 /** 
450  * @brief Returns left and right paths and recursive from project file
451  * 
452  * @param [out] sLeft Left path
453  * @param [out] sRight Right path
454  * @param [out] bSubFolders If TRUE subfolders included (recursive compare)
455  */
456 void ProjectFile::GetPaths(CString & sLeft, CString & sRight,
457         BOOL & bSubfolders) const
458 {
459         if (HasLeft())
460                 sLeft = GetLeft();
461         if (HasRight())
462                 sRight = GetRight();
463         if (HasSubfolders())
464                 bSubfolders = (GetSubfolders() == 1);
465 }