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 // ID line follows -- this is updated by CVS
23 // $Id: ProjectFile.cpp 7081 2010-01-01 20:33:30Z kimmov $
26 #include <scew/scew.h>
27 #include "UnicodeString.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 Middle_element_name[] = "middle";
57 const char Right_element_name[] = "right";
58 const char Filter_element_name[] = "filter";
59 const char Subfolders_element_name[] = "subfolders";
60 const char Left_ro_element_name[] = "left-readonly";
61 const char Middle_ro_element_name[] = "middle-readonly";
62 const char Right_ro_element_name[] = "right-readonly";
65 * @brief Standard constructor.
67 ProjectFile::ProjectFile()
72 , m_bHasSubfolders(FALSE)
74 , m_bLeftReadOnly(FALSE)
75 , m_bMiddleReadOnly(FALSE)
76 , m_bRightReadOnly(FALSE)
81 * @brief Open given path-file and read data from it to member variables.
82 * @param [in] path Path to project file.
83 * @param [out] sError Error string if error happened.
84 * @return TRUE if reading succeeded, FALSE if error happened.
86 BOOL ProjectFile::Read(LPCTSTR path, String *sError)
89 scew_tree* tree = NULL;
90 scew_parser* parser = NULL;
92 parser = scew_parser_create();
93 scew_parser_ignore_whitespaces(parser, 1);
95 scew_reader *reader = NULL;
96 FILE * fp = _tfopen(path, _T("r"));
99 reader = scew_reader_fp_create(fp);
102 tree = scew_parser_load (parser, reader);
106 scew_element * root = GetRootElement(tree);
109 // Currently our content is paths, so expect
110 // having paths in valid project file!
111 if (GetPathsData(root))
117 scew_tree_free(tree);
118 scew_reader_free(reader);
120 /* Frees the SCEW parser */
121 scew_parser_free(parser);
128 * @brief Return project file XML's root element.
129 * @param [in] tree XML tree we got from the parser.
130 * @return Root element pointer.
132 scew_element* ProjectFile::GetRootElement(scew_tree * tree)
134 scew_element * root = NULL;
138 root = scew_tree_root(tree);
143 // Make sure we have correct root element
144 if (strcmp(Root_element_name, scew_element_name(root)) != 0)
153 * @brief Reads the paths data from the XML data.
154 * This function reads the paths data inside given element in XML data.
155 * @param [in] parent Parent element for the paths data.
156 * @return TRUE if pathdata was found from the file.
158 BOOL ProjectFile::GetPathsData(scew_element * parent)
161 BOOL bFoundPaths = FALSE;
162 scew_element *paths = NULL;
166 paths = scew_element_by_name(parent, Paths_element_name);
172 scew_element *left = NULL;
173 scew_element *middle = NULL;
174 scew_element *right = NULL;
175 scew_element *filter = NULL;
176 scew_element *subfolders = NULL;
177 scew_element *left_ro = NULL;
178 scew_element *middle_ro = NULL;
179 scew_element *right_ro = NULL;
181 left = scew_element_by_name(paths, Left_element_name);
182 middle = scew_element_by_name(paths, Middle_element_name);
183 right = scew_element_by_name(paths, Right_element_name);
184 filter = scew_element_by_name(paths, Filter_element_name);
185 subfolders = scew_element_by_name(paths, Subfolders_element_name);
186 left_ro = scew_element_by_name(paths, Left_ro_element_name);
187 middle_ro = scew_element_by_name(paths, Middle_ro_element_name);
188 right_ro = scew_element_by_name(paths, Right_ro_element_name);
193 path = scew_element_contents(left);
194 m_paths.SetLeft(UTF82T(path));
200 path = scew_element_contents(middle);
201 m_paths.SetMiddle(UTF82T(path));
207 path = scew_element_contents(right);
208 m_paths.SetRight(UTF82T(path));
213 LPCSTR filtername = NULL;
214 filtername = scew_element_contents(filter);
215 m_filter = UTF82T(filtername);
220 LPCSTR folders = NULL;
221 folders = scew_element_contents(subfolders);
222 m_subfolders = atoi(folders);
223 m_bHasSubfolders = TRUE;
227 LPCSTR readonly = NULL;
228 readonly = scew_element_contents(left_ro);
229 m_bLeftReadOnly = (atoi(readonly) != 0);
233 LPCSTR readonly = NULL;
234 readonly = scew_element_contents(middle_ro);
235 m_bMiddleReadOnly = (atoi(readonly) != 0);
239 LPCSTR readonly = NULL;
240 readonly = scew_element_contents(right_ro);
241 m_bRightReadOnly = (atoi(readonly) != 0);
248 * @brief Save data from member variables to path-file.
249 * @param [in] path Path to project file.
250 * @param [out] sError Error string if error happened.
251 * @return TRUE if saving succeeded, FALSE if error happened.
253 BOOL ProjectFile::Save(LPCTSTR path, String *sError)
256 scew_tree* tree = NULL;
257 scew_element* root = NULL;
258 scew_element* paths = NULL;
260 tree = scew_tree_create();
261 root = scew_tree_set_root(tree, Root_element_name);
264 paths = AddPathsElement(root);
271 AddPathsContent(paths);
276 scew_tree_set_xml_encoding(tree, "UTF-8");
278 scew_writer *writer = NULL;
279 scew_printer *printer = NULL;
280 FILE * fp = _tfopen(path, _T("w"));
283 writer = scew_writer_fp_create(fp);
286 printer = scew_printer_create(writer);
288 if (!scew_printer_print_tree(printer, tree) ||
289 !scew_printf(_XT("\n")))
292 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
298 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
307 /* Frees the SCEW tree */
308 scew_tree_free(tree);
309 scew_writer_free(writer);
310 scew_printer_free(printer);
312 if (success == FALSE)
314 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
320 * @brief Add paths element into XML tree.
321 * @param [in] parent Parent element for the paths element.
322 * @return pointer to added paths element.
324 scew_element* ProjectFile::AddPathsElement(scew_element * parent)
326 scew_element* element = NULL;
327 element = scew_element_add(parent, Paths_element_name);
332 * @brief Covert characters that are unsafe for use in XML
333 * @param [in] str The string to be converted
334 * @return The converted string
336 static String EscapeXML(const String &str)
338 String escapedStr = str;
339 string_replace(escapedStr, _T("&"), _T("&"));
340 string_replace(escapedStr, _T("<"), _T("<"));
341 string_replace(escapedStr, _T(">"), _T(">"));
346 * @brief Add paths data to the XML tree.
347 * This function adds our paths data to the XML tree.
348 * @param [in] parent Parent element for paths data.
349 * @return TRUE if we succeeded, FALSE otherwise.
351 BOOL ProjectFile::AddPathsContent(scew_element * parent)
354 scew_element* element = NULL;
356 if (!m_paths.GetLeft().empty())
358 element = scew_element_add(parent, Left_element_name);
359 scew_element_set_contents(element, T2UTF8(EscapeXML(m_paths.GetLeft()).c_str()));
362 if (!m_paths.GetMiddle().empty())
364 element = scew_element_add(parent, Middle_element_name);
365 scew_element_set_contents(element, T2UTF8(EscapeXML(m_paths.GetMiddle()).c_str()));
368 if (!m_paths.GetRight().empty())
370 element = scew_element_add(parent, Right_element_name);
371 scew_element_set_contents(element, T2UTF8(EscapeXML(m_paths.GetRight()).c_str()));
374 if (!m_filter.empty())
376 element = scew_element_add(parent, Filter_element_name);
377 String filter = m_filter;
378 scew_element_set_contents(element, T2UTF8(EscapeXML(filter).c_str()));
381 element = scew_element_add(parent, Subfolders_element_name);
382 if (m_subfolders != 0)
383 scew_element_set_contents(element, "1");
385 scew_element_set_contents(element, "0");
387 element = scew_element_add(parent, Left_ro_element_name);
389 scew_element_set_contents(element, "1");
391 scew_element_set_contents(element, "0");
393 if (!m_paths.GetMiddle().empty())
395 element = scew_element_add(parent, Middle_ro_element_name);
396 if (m_bMiddleReadOnly)
397 scew_element_set_contents(element, "1");
399 scew_element_set_contents(element, "0");
401 element = scew_element_add(parent, Right_ro_element_name);
402 if (m_bRightReadOnly)
403 scew_element_set_contents(element, "1");
405 scew_element_set_contents(element, "0");
411 * @brief Returns if left path is defined in project file.
412 * @return TRUE if project file has left path.
414 BOOL ProjectFile::HasLeft() const
420 * @brief Returns if middle path is defined.
422 BOOL ProjectFile::HasMiddle() const
428 * @brief Returns if right path is defined in project file.
429 * @return TRUE if project file has right path.
431 BOOL ProjectFile::HasRight() const
437 * @brief Returns if filter is defined in project file.
438 * @return TRUE if project file has filter.
440 BOOL ProjectFile::HasFilter() const
446 * @brief Returns if subfolder is defined in projectfile.
447 * @return TRUE if project file has subfolder definition.
449 BOOL ProjectFile::HasSubfolders() const
451 return m_bHasSubfolders;
455 * @brief Returns left path.
456 * @param [out] pReadOnly TRUE if readonly was specified for path.
459 String ProjectFile::GetLeft(BOOL * pReadOnly /*=NULL*/) const
462 *pReadOnly = m_bLeftReadOnly;
463 return m_paths.GetLeft();
467 * @brief Returns if left path is specified read-only.
468 * @return TRUE if left path is read-only, FALSE otherwise.
470 BOOL ProjectFile::GetLeftReadOnly() const
472 return m_bLeftReadOnly;
476 * @brief Set left path, returns old left path.
477 * @param [in] sLeft Left path.
478 * @param [in] bReadOnly Will path be recorded read-only?
480 void ProjectFile::SetLeft(const String& sLeft, const BOOL * pReadOnly /*=NULL*/)
482 m_paths.SetLeft(sLeft.c_str(), false);
484 m_bLeftReadOnly = *pReadOnly;
488 * @brief Returns middle path.
489 * @param [out] pReadOnly TRUE if readonly was specified for path.
491 String ProjectFile::GetMiddle(BOOL * pReadOnly /*=NULL*/) const
494 *pReadOnly = m_bMiddleReadOnly;
495 return m_paths.GetMiddle();
499 * @brief Returns if middle path is specified read-only.
501 BOOL ProjectFile::GetMiddleReadOnly() const
503 return m_bMiddleReadOnly;
507 * @brief Set middle path, returns old middle path.
508 * @param [in] sMiddle Middle path.
509 * @param [in] bReadOnly Will path be recorded read-only?
511 void ProjectFile::SetMiddle(const String& sMiddle, const BOOL * pReadOnly /*=NULL*/)
513 m_paths.SetMiddle(sMiddle.c_str(), false);
515 m_bMiddleReadOnly = *pReadOnly;
521 * @brief Returns right path.
522 * @param [out] pReadOnly TRUE if readonly was specified for path.
523 * @return Right path.
525 String ProjectFile::GetRight(BOOL * pReadOnly /*=NULL*/) const
528 *pReadOnly = m_bRightReadOnly;
529 return m_paths.GetRight();
533 * @brief Returns if right path is specified read-only.
534 * @return TRUE if right path is read-only, FALSE otherwise.
536 BOOL ProjectFile::GetRightReadOnly() const
538 return m_bRightReadOnly;
542 * @brief Set right path, returns old right path.
543 * @param [in] sRight Right path.
544 * @param [in] bReadOnly Will path be recorded read-only?
546 void ProjectFile::SetRight(const String& sRight, const BOOL * pReadOnly /*=NULL*/)
548 m_paths.SetRight(sRight.c_str(), false);
550 m_bRightReadOnly = *pReadOnly;
554 * @brief Returns filter.
555 * @return Filter string.
557 String ProjectFile::GetFilter() const
564 * @param [in] sFilter New filter string to set.
566 void ProjectFile::SetFilter(const String& sFilter)
572 * @brief Returns subfolder included -setting.
573 * @return != 0 if subfolders are included.
575 int ProjectFile::GetSubfolders() const
581 * @brief set subfolder.
582 * @param [in] iSubfolder New value for subfolder inclusion.
584 void ProjectFile::SetSubfolders(int iSubfolder)
586 m_subfolders = iSubfolder ? 1 : 0;
592 * @param [in] files Files in project
593 * @param [in] bSubFolders If TRUE subfolders included (recursive compare)
595 void ProjectFile::SetPaths(const PathContext& files, BOOL bSubfolders)
598 m_subfolders = bSubfolders;
602 * @brief Returns left and right paths and recursive from project file
604 * @param [out] files Files in project
605 * @param [out] bSubFolders If TRUE subfolders included (recursive compare)
607 void ProjectFile::GetPaths(PathContext& files, BOOL & bSubfolders) const
611 bSubfolders = (GetSubfolders() == 1);