OSDN Git Service

PATCH: [ 1589427 ] Add back read-only handling 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  * @bug This doesn't handle unicode paths!
56  */
57 BOOL ProjectFile::Read(LPCTSTR path, CString *sError)
58 {
59         BOOL loaded = FALSE;
60         LPCSTR pathAnsi;
61
62 #ifdef UNICODE
63         USES_CONVERSION;
64         pathAnsi = T2A(path);
65 #else
66         pathAnsi = path;
67 #endif
68
69     scew_tree* tree = NULL;
70     scew_parser* parser = NULL;
71
72     parser = scew_parser_create();
73     scew_parser_ignore_whitespaces(parser, 1);
74
75         if (scew_parser_load_file(parser, pathAnsi))
76         {
77                 tree = scew_parser_tree(parser);
78
79                 scew_element * root = GetRootElement(tree);
80                 if (root)
81                 {
82                         loaded = TRUE;
83                         GetPathsData(root);
84                 };
85         }
86     scew_tree_free(tree);
87
88     /* Frees the SCEW parser */
89     scew_parser_free(parser);
90
91         return loaded;
92 }
93
94 /** 
95  * @brief Return project file XML's root element.
96  * @param [in] tree XML tree we got from the parser.
97  * @return Root element pointer.
98  */
99 scew_element* ProjectFile::GetRootElement(scew_tree * tree)
100 {
101         scew_element * root = NULL;
102
103         if (tree != NULL)
104         {
105                 root = scew_tree_root(tree);
106         }
107
108         if (root != NULL)
109         {
110                 // Make sure we have correct root element
111                 if (_tcscmp(Root_element_name, scew_element_name(root)) != 0)
112                 {
113                         root = NULL;
114                 }
115         }
116         return root;
117 }
118
119 /** 
120  * @brief Reads the paths data from the XML data.
121  * This function reads the paths data inside given element in XML data.
122  * @param [in] parent Parent element for the paths data.
123  */
124 void ProjectFile::GetPathsData(scew_element * parent)
125 {
126         scew_element *paths = NULL;
127
128         if (parent != NULL)
129         {
130                 paths = scew_element_by_name(parent, Paths_element_name);
131         }
132
133         if (paths != NULL)
134         {
135                 scew_element *left = NULL;
136                 scew_element *right = NULL;
137                 scew_element *filter = NULL;
138                 scew_element *subfolders = NULL;
139                 scew_element *left_ro = NULL;
140                 scew_element *right_ro = NULL;
141
142                 left = scew_element_by_name(paths, Left_element_name);
143                 right = scew_element_by_name(paths, Right_element_name);
144                 filter = scew_element_by_name(paths, Filter_element_name);
145                 subfolders = scew_element_by_name(paths, Subfolders_element_name);
146                 left_ro = scew_element_by_name(paths, Left_ro_element_name);
147                 right_ro = scew_element_by_name(paths, Right_ro_element_name);
148
149                 if (left)
150                 {
151                         LPCTSTR path = NULL;
152                         path = scew_element_contents(right);
153                         m_leftFile = path;
154                 }
155                 if (right)
156                 {
157                         LPCTSTR path = NULL;
158                         path = scew_element_contents(right);
159                         m_rightFile = path;
160                 }
161                 if (filter)
162                 {
163                         LPCTSTR filtername = NULL;
164                         filtername = scew_element_contents(filter);
165                         m_filter = filtername;
166                 }
167                 if (subfolders)
168                 {
169                         LPCTSTR folders = NULL;
170                         folders = scew_element_contents(subfolders);
171                         m_subfolders = _ttoi(folders);
172                 }
173                 if (left_ro)
174                 {
175                         LPCTSTR readonly = NULL;
176                         readonly = scew_element_contents(left_ro);
177                         m_bLeftReadOnly = (_ttoi(readonly) != 0);
178                 }
179                 if (right_ro)
180                 {
181                         LPCTSTR readonly = NULL;
182                         readonly = scew_element_contents(right_ro);
183                         m_bRightReadOnly = (_ttoi(readonly) != 0);
184                 }
185         }
186 }
187
188 /** 
189  * @brief Save data from member variables to path-file.
190  * @param [in] path Path to project file.
191  * @param [out] sError Error string if error happened.
192  * @return TRUE if saving succeeded, FALSE if error happened.
193  */
194 BOOL ProjectFile::Save(LPCTSTR path, CString *sError)
195 {
196         BOOL success = TRUE;
197         LPCSTR pathAnsi;
198
199 #ifdef UNICODE
200         USES_CONVERSION;
201         pathAnsi = T2A(path);
202 #else
203         pathAnsi = path;
204 #endif
205         
206         scew_tree* tree = NULL;
207         scew_element* root = NULL;
208         scew_element* paths = NULL;
209
210         tree = scew_tree_create();
211         root = scew_tree_add_root(tree, Root_element_name);
212         if (root != NULL)
213         {
214                 paths = AddPathsElement(root);
215         }
216         else
217                 success = FALSE;
218
219         if (paths != NULL)
220         {
221                 AddPathsContent(paths);
222         }
223         else
224                 success = FALSE;
225         
226         scew_tree_set_xml_encoding(tree, _T("UTF-8"));
227
228         // Set the XML file standalone
229         scew_tree_set_xml_standalone(tree, 1);
230
231         if (!scew_writer_tree_file(tree, pathAnsi))
232                 success = FALSE;
233         
234         /* Frees the SCEW tree */
235         scew_tree_free(tree);
236
237         return success;
238         //      return Serialize(true, path, sError);
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 }