1 /////////////////////////////////////////////////////////////////////////////
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.
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.
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 /////////////////////////////////////////////////////////////////////////////
18 * @file ProjectFile.cpp
20 * @brief Implementation file for ProjectFile class.
22 // RCS ID line follows -- this is updated by CVS
26 #include <scew/scew.h>
28 #include "ProjectFile.h"
31 // ATL conversion macro hack for UTF-8 conversion
32 #define UTF82W(lpa) (\
33 ((_lpa = lpa) == NULL) ? NULL : (\
34 _convert = (lstrlenA(_lpa)+1),\
35 AtlA2WHelper((LPWSTR) alloca(_convert*2), _lpa, _convert, CP_UTF8)))
37 #define W2UTF8(lpw) (\
38 ((_lpw = lpw) == NULL) ? NULL : (\
39 _convert = (lstrlenW(_lpw)+1)*6,\
40 AtlW2AHelper((LPSTR) alloca(_convert), _lpw, _convert, CP_UTF8)))
42 #define UTF82A(lpu) W2A(UTF82W(lpu))
43 #define A2UTF8(lpa) W2UTF8(A2W(lpa))
45 # define UTF82T(lpu) UTF82W(lpu)
46 # define T2UTF8(lpw) W2UTF8(lpw)
48 # define UTF82T(lpu) UTF82A(lpu)
49 # define T2UTF8(lpw) A2UTF8(lpw)
52 // Constants for xml element names
53 const char Root_element_name[] = "project";
54 const char Paths_element_name[] = "paths";
55 const char Left_element_name[] = "left";
56 const char Right_element_name[] = "right";
57 const char Filter_element_name[] = "filter";
58 const char Subfolders_element_name[] = "subfolders";
59 const char Left_ro_element_name[] = "left-readonly";
60 const char Right_ro_element_name[] = "right-readonly";
63 * @brief Standard constructor.
65 ProjectFile::ProjectFile()
69 , m_bHasSubfolders(FALSE)
71 , m_bLeftReadOnly(FALSE)
72 , m_bRightReadOnly(FALSE)
77 * @brief Open given path-file and read data from it to member variables.
78 * @param [in] path Path to project file.
79 * @param [out] sError Error string if error happened.
80 * @return TRUE if reading succeeded, FALSE if error happened.
82 BOOL ProjectFile::Read(LPCTSTR path, String *sError)
85 scew_tree* tree = NULL;
86 scew_parser* parser = NULL;
88 parser = scew_parser_create();
89 scew_parser_ignore_whitespaces(parser, 1);
91 FILE * fp = _tfopen(path, _T("r"));
94 if (scew_parser_load_file_fp(parser, fp))
96 tree = scew_parser_tree(parser);
98 scew_element * root = GetRootElement(tree);
101 // Currently our content is paths, so expect
102 // having paths in valid project file!
103 if (GetPathsData(root))
107 scew_tree_free(tree);
109 /* Frees the SCEW parser */
110 scew_parser_free(parser);
117 * @brief Return project file XML's root element.
118 * @param [in] tree XML tree we got from the parser.
119 * @return Root element pointer.
121 scew_element* ProjectFile::GetRootElement(scew_tree * tree)
123 scew_element * root = NULL;
127 root = scew_tree_root(tree);
132 // Make sure we have correct root element
133 if (strcmp(Root_element_name, scew_element_name(root)) != 0)
142 * @brief Reads the paths data from the XML data.
143 * This function reads the paths data inside given element in XML data.
144 * @param [in] parent Parent element for the paths data.
145 * @return TRUE if pathdata was found from the file.
147 BOOL ProjectFile::GetPathsData(scew_element * parent)
150 BOOL bFoundPaths = FALSE;
151 scew_element *paths = NULL;
155 paths = scew_element_by_name(parent, Paths_element_name);
161 scew_element *left = NULL;
162 scew_element *right = NULL;
163 scew_element *filter = NULL;
164 scew_element *subfolders = NULL;
165 scew_element *left_ro = NULL;
166 scew_element *right_ro = NULL;
168 left = scew_element_by_name(paths, Left_element_name);
169 right = scew_element_by_name(paths, Right_element_name);
170 filter = scew_element_by_name(paths, Filter_element_name);
171 subfolders = scew_element_by_name(paths, Subfolders_element_name);
172 left_ro = scew_element_by_name(paths, Left_ro_element_name);
173 right_ro = scew_element_by_name(paths, Right_ro_element_name);
178 path = scew_element_contents(left);
179 m_leftFile = UTF82T(path);
185 path = scew_element_contents(right);
186 m_rightFile = UTF82T(path);
191 LPCSTR filtername = NULL;
192 filtername = scew_element_contents(filter);
193 m_filter = UTF82T(filtername);
198 LPCSTR folders = NULL;
199 folders = scew_element_contents(subfolders);
200 m_subfolders = atoi(folders);
201 m_bHasSubfolders = TRUE;
205 LPCSTR readonly = NULL;
206 readonly = scew_element_contents(left_ro);
207 m_bLeftReadOnly = (atoi(readonly) != 0);
211 LPCSTR readonly = NULL;
212 readonly = scew_element_contents(right_ro);
213 m_bRightReadOnly = (atoi(readonly) != 0);
220 * @brief Save data from member variables to path-file.
221 * @param [in] path Path to project file.
222 * @param [out] sError Error string if error happened.
223 * @return TRUE if saving succeeded, FALSE if error happened.
225 BOOL ProjectFile::Save(LPCTSTR path, String *sError)
228 scew_tree* tree = NULL;
229 scew_element* root = NULL;
230 scew_element* paths = NULL;
232 tree = scew_tree_create();
233 root = scew_tree_add_root(tree, Root_element_name);
236 paths = AddPathsElement(root);
243 AddPathsContent(paths);
248 scew_tree_set_xml_encoding(tree, "UTF-8");
250 // Set the XML file standalone
251 scew_tree_set_xml_standalone(tree, 1);
253 FILE * fp = _tfopen(path, _T("w"));
256 if (!scew_writer_tree_fp(tree, fp))
259 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
268 /* Frees the SCEW tree */
269 scew_tree_free(tree);
271 if (success == FALSE)
273 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
279 * @brief Add paths element into XML tree.
280 * @param [in] parent Parent element for the paths element.
281 * @return pointer to added paths element.
283 scew_element* ProjectFile::AddPathsElement(scew_element * parent)
285 scew_element* element = NULL;
286 element = scew_element_add(parent, Paths_element_name);
291 * @brief Covert characters that are unsafe for use in XML
292 * @param [in] str The string to be converted
293 * @return The converted string
295 static String EscapeXML(const String &str)
297 String escapedStr = str;
298 string_replace(escapedStr, _T("&"), _T("&"));
299 string_replace(escapedStr, _T("<"), _T("<"));
300 string_replace(escapedStr, _T(">"), _T(">"));
305 * @brief Add paths data to the XML tree.
306 * This function adds our paths data to the XML tree.
307 * @param [in] parent Parent element for paths data.
308 * @return TRUE if we succeeded, FALSE otherwise.
310 BOOL ProjectFile::AddPathsContent(scew_element * parent)
313 scew_element* element = NULL;
315 if (!m_leftFile.IsEmpty())
317 element = scew_element_add(parent, Left_element_name);
318 String path = m_leftFile;
319 scew_element_set_contents(element, T2UTF8(EscapeXML(path).c_str()));
322 if (!m_rightFile.IsEmpty())
324 element = scew_element_add(parent, Right_element_name);
325 String path = m_rightFile;
326 scew_element_set_contents(element, T2UTF8(EscapeXML(path).c_str()));
329 if (!m_filter.IsEmpty())
331 element = scew_element_add(parent, Filter_element_name);
332 String filter = m_filter;
333 scew_element_set_contents(element, T2UTF8(EscapeXML(filter).c_str()));
336 element = scew_element_add(parent, Subfolders_element_name);
337 if (m_subfolders != 0)
338 scew_element_set_contents(element, "1");
340 scew_element_set_contents(element, "0");
342 element = scew_element_add(parent, Left_ro_element_name);
344 scew_element_set_contents(element, "1");
346 scew_element_set_contents(element, "0");
348 element = scew_element_add(parent, Right_ro_element_name);
349 if (m_bRightReadOnly)
350 scew_element_set_contents(element, "1");
352 scew_element_set_contents(element, "0");
358 * @brief Returns if left path is defined in project file.
359 * @return TRUE if project file has left path.
361 BOOL ProjectFile::HasLeft() const
367 * @brief Returns if right path is defined in project file.
368 * @return TRUE if project file has right path.
370 BOOL ProjectFile::HasRight() const
376 * @brief Returns if filter is defined in project file.
377 * @return TRUE if project file has filter.
379 BOOL ProjectFile::HasFilter() const
385 * @brief Returns if subfolder is defined in projectfile.
386 * @return TRUE if project file has subfolder definition.
388 BOOL ProjectFile::HasSubfolders() const
390 return m_bHasSubfolders;
394 * @brief Returns left path.
395 * @param [out] pReadOnly TRUE if readonly was specified for path.
397 CString ProjectFile::GetLeft(BOOL * pReadOnly /*=NULL*/) const
400 *pReadOnly = m_bLeftReadOnly;
405 * @brief Returns if left path is specified read-only.
407 BOOL ProjectFile::GetLeftReadOnly() const
409 return m_bLeftReadOnly;
413 * @brief Set left path, returns old left path.
414 * @param [in] sLeft Left path.
415 * @param [in] bReadOnly Will path be recorded read-only?
417 CString ProjectFile::SetLeft(const CString& sLeft, const BOOL * pReadOnly /*=NULL*/)
419 CString sLeftOld = GetLeft();
422 m_bLeftReadOnly = *pReadOnly;
428 * @brief Returns right path.
429 * @param [out] pReadOnly TRUE if readonly was specified for path.
431 CString ProjectFile::GetRight(BOOL * pReadOnly /*=NULL*/) const
434 *pReadOnly = m_bRightReadOnly;
439 * @brief Returns if right path is specified read-only.
441 BOOL ProjectFile::GetRightReadOnly() const
443 return m_bRightReadOnly;
447 * @brief Set right path, returns old right path.
448 * @param [in] sRight Right path.
449 * @param [in] bReadOnly Will path be recorded read-only?
451 CString ProjectFile::SetRight(const CString& sRight, const BOOL * pReadOnly /*=NULL*/)
453 CString sRightOld = GetRight();
454 m_rightFile = sRight;
456 m_bRightReadOnly = *pReadOnly;
462 * @brief Returns filter.
464 CString ProjectFile::GetFilter() const
470 * @brief Set filter, returns old filter.
472 CString ProjectFile::SetFilter(const CString& sFilter)
474 CString sFilterOld = GetFilter();
481 * @brief Returns subfolder included -setting.
483 int ProjectFile::GetSubfolders() const
489 * @brief set subfolder, returns old subfolder value.
491 int ProjectFile::SetSubfolders(const int iSubfolder)
493 int iSubfoldersOld = GetSubfolders();
494 m_subfolders = iSubfolder ? 1 : 0;
496 return iSubfoldersOld;
500 * @brief Returns left and right paths and recursive from project file
502 * @param [out] sLeft Left path
503 * @param [out] sRight Right path
504 * @param [out] bSubFolders If TRUE subfolders included (recursive compare)
506 void ProjectFile::GetPaths(CString & sLeft, CString & sRight,
507 BOOL & bSubfolders) const
514 bSubfolders = (GetSubfolders() == 1);