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
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))
44 # define UTF82T(lpu) UTF82W(lpu)
45 # define T2UTF8(lpw) W2UTF8(lpw)
47 // Constants for xml element names
48 const char Root_element_name[] = "project";
49 const char Paths_element_name[] = "paths";
50 const char Left_element_name[] = "left";
51 const char Right_element_name[] = "right";
52 const char Filter_element_name[] = "filter";
53 const char Subfolders_element_name[] = "subfolders";
54 const char Left_ro_element_name[] = "left-readonly";
55 const char Right_ro_element_name[] = "right-readonly";
58 * @brief Standard constructor.
60 ProjectFile::ProjectFile()
64 , m_bHasSubfolders(FALSE)
66 , m_bLeftReadOnly(FALSE)
67 , m_bRightReadOnly(FALSE)
72 * @brief Open given path-file and read data from it to member variables.
73 * @param [in] path Path to project file.
74 * @param [out] sError Error string if error happened.
75 * @return TRUE if reading succeeded, FALSE if error happened.
77 BOOL ProjectFile::Read(LPCTSTR path, String *sError)
80 scew_tree* tree = NULL;
81 scew_parser* parser = NULL;
83 parser = scew_parser_create();
84 scew_parser_ignore_whitespaces(parser, 1);
86 scew_reader *reader = NULL;
87 FILE * fp = _tfopen(path, _T("r"));
90 reader = scew_reader_fp_create(fp);
93 tree = scew_parser_load (parser, reader);
97 scew_element * root = GetRootElement(tree);
100 // Currently our content is paths, so expect
101 // having paths in valid project file!
102 if (GetPathsData(root))
108 scew_tree_free(tree);
109 scew_reader_free(reader);
111 /* Frees the SCEW parser */
112 scew_parser_free(parser);
119 * @brief Return project file XML's root element.
120 * @param [in] tree XML tree we got from the parser.
121 * @return Root element pointer.
123 scew_element* ProjectFile::GetRootElement(scew_tree * tree)
125 scew_element * root = NULL;
129 root = scew_tree_root(tree);
134 // Make sure we have correct root element
135 if (strcmp(Root_element_name, scew_element_name(root)) != 0)
144 * @brief Reads the paths data from the XML data.
145 * This function reads the paths data inside given element in XML data.
146 * @param [in] parent Parent element for the paths data.
147 * @return TRUE if pathdata was found from the file.
149 BOOL ProjectFile::GetPathsData(scew_element * parent)
152 BOOL bFoundPaths = FALSE;
153 scew_element *paths = NULL;
157 paths = scew_element_by_name(parent, Paths_element_name);
163 scew_element *left = NULL;
164 scew_element *right = NULL;
165 scew_element *filter = NULL;
166 scew_element *subfolders = NULL;
167 scew_element *left_ro = NULL;
168 scew_element *right_ro = NULL;
170 left = scew_element_by_name(paths, Left_element_name);
171 right = scew_element_by_name(paths, Right_element_name);
172 filter = scew_element_by_name(paths, Filter_element_name);
173 subfolders = scew_element_by_name(paths, Subfolders_element_name);
174 left_ro = scew_element_by_name(paths, Left_ro_element_name);
175 right_ro = scew_element_by_name(paths, Right_ro_element_name);
180 path = scew_element_contents(left);
181 m_leftFile = UTF82T(path);
187 path = scew_element_contents(right);
188 m_rightFile = UTF82T(path);
193 LPCSTR filtername = NULL;
194 filtername = scew_element_contents(filter);
195 m_filter = UTF82T(filtername);
200 LPCSTR folders = NULL;
201 folders = scew_element_contents(subfolders);
202 m_subfolders = atoi(folders);
203 m_bHasSubfolders = TRUE;
207 LPCSTR readonly = NULL;
208 readonly = scew_element_contents(left_ro);
209 m_bLeftReadOnly = (atoi(readonly) != 0);
213 LPCSTR readonly = NULL;
214 readonly = scew_element_contents(right_ro);
215 m_bRightReadOnly = (atoi(readonly) != 0);
222 * @brief Save data from member variables to path-file.
223 * @param [in] path Path to project file.
224 * @param [out] sError Error string if error happened.
225 * @return TRUE if saving succeeded, FALSE if error happened.
227 BOOL ProjectFile::Save(LPCTSTR path, String *sError)
230 scew_tree* tree = NULL;
231 scew_element* root = NULL;
232 scew_element* paths = NULL;
234 tree = scew_tree_create();
235 root = scew_tree_set_root(tree, Root_element_name);
238 paths = AddPathsElement(root);
245 AddPathsContent(paths);
250 scew_tree_set_xml_encoding(tree, "UTF-8");
252 scew_writer *writer = NULL;
253 scew_printer *printer = NULL;
254 FILE * fp = _tfopen(path, _T("w"));
257 writer = scew_writer_fp_create(fp);
260 printer = scew_printer_create(writer);
262 if (!scew_printer_print_tree(printer, tree) ||
263 !scew_printf(_XT("\n")))
266 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
272 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
281 /* Frees the SCEW tree */
282 scew_tree_free(tree);
283 scew_writer_free(writer);
284 scew_printer_free(printer);
286 if (success == FALSE)
288 *sError = theApp.LoadString(IDS_FILEWRITE_ERROR);
294 * @brief Add paths element into XML tree.
295 * @param [in] parent Parent element for the paths element.
296 * @return pointer to added paths element.
298 scew_element* ProjectFile::AddPathsElement(scew_element * parent)
300 scew_element* element = NULL;
301 element = scew_element_add(parent, Paths_element_name);
306 * @brief Covert characters that are unsafe for use in XML
307 * @param [in] str The string to be converted
308 * @return The converted string
310 static String EscapeXML(const String &str)
312 String escapedStr = str;
313 string_replace(escapedStr, _T("&"), _T("&"));
314 string_replace(escapedStr, _T("<"), _T("<"));
315 string_replace(escapedStr, _T(">"), _T(">"));
320 * @brief Add paths data to the XML tree.
321 * This function adds our paths data to the XML tree.
322 * @param [in] parent Parent element for paths data.
323 * @return TRUE if we succeeded, FALSE otherwise.
325 BOOL ProjectFile::AddPathsContent(scew_element * parent)
328 scew_element* element = NULL;
330 if (!m_leftFile.empty())
332 element = scew_element_add(parent, Left_element_name);
333 String path = m_leftFile;
334 scew_element_set_contents(element, T2UTF8(EscapeXML(path).c_str()));
337 if (!m_rightFile.empty())
339 element = scew_element_add(parent, Right_element_name);
340 String path = m_rightFile;
341 scew_element_set_contents(element, T2UTF8(EscapeXML(path).c_str()));
344 if (!m_filter.empty())
346 element = scew_element_add(parent, Filter_element_name);
347 String filter = m_filter;
348 scew_element_set_contents(element, T2UTF8(EscapeXML(filter).c_str()));
351 element = scew_element_add(parent, Subfolders_element_name);
352 if (m_subfolders != 0)
353 scew_element_set_contents(element, "1");
355 scew_element_set_contents(element, "0");
357 element = scew_element_add(parent, Left_ro_element_name);
359 scew_element_set_contents(element, "1");
361 scew_element_set_contents(element, "0");
363 element = scew_element_add(parent, Right_ro_element_name);
364 if (m_bRightReadOnly)
365 scew_element_set_contents(element, "1");
367 scew_element_set_contents(element, "0");
373 * @brief Returns if left path is defined in project file.
374 * @return TRUE if project file has left path.
376 BOOL ProjectFile::HasLeft() const
382 * @brief Returns if right path is defined in project file.
383 * @return TRUE if project file has right path.
385 BOOL ProjectFile::HasRight() const
391 * @brief Returns if filter is defined in project file.
392 * @return TRUE if project file has filter.
394 BOOL ProjectFile::HasFilter() const
400 * @brief Returns if subfolder is defined in projectfile.
401 * @return TRUE if project file has subfolder definition.
403 BOOL ProjectFile::HasSubfolders() const
405 return m_bHasSubfolders;
409 * @brief Returns left path.
410 * @param [out] pReadOnly TRUE if readonly was specified for path.
413 String ProjectFile::GetLeft(BOOL * pReadOnly /*=NULL*/) const
416 *pReadOnly = m_bLeftReadOnly;
421 * @brief Returns if left path is specified read-only.
422 * @return TRUE if left path is read-only, FALSE otherwise.
424 BOOL ProjectFile::GetLeftReadOnly() const
426 return m_bLeftReadOnly;
430 * @brief Set left path, returns old left path.
431 * @param [in] sLeft Left path.
432 * @param [in] bReadOnly Will path be recorded read-only?
434 void ProjectFile::SetLeft(const String& sLeft, const BOOL * pReadOnly /*=NULL*/)
438 m_bLeftReadOnly = *pReadOnly;
442 * @brief Returns right path.
443 * @param [out] pReadOnly TRUE if readonly was specified for path.
444 * @return Right path.
446 String ProjectFile::GetRight(BOOL * pReadOnly /*=NULL*/) const
449 *pReadOnly = m_bRightReadOnly;
454 * @brief Returns if right path is specified read-only.
455 * @return TRUE if right path is read-only, FALSE otherwise.
457 BOOL ProjectFile::GetRightReadOnly() const
459 return m_bRightReadOnly;
463 * @brief Set right path, returns old right path.
464 * @param [in] sRight Right path.
465 * @param [in] bReadOnly Will path be recorded read-only?
467 void ProjectFile::SetRight(const String& sRight, const BOOL * pReadOnly /*=NULL*/)
469 m_rightFile = sRight;
471 m_bRightReadOnly = *pReadOnly;
475 * @brief Returns filter.
476 * @return Filter string.
478 String ProjectFile::GetFilter() const
485 * @param [in] sFilter New filter string to set.
487 void ProjectFile::SetFilter(const String& sFilter)
493 * @brief Returns subfolder included -setting.
494 * @return != 0 if subfolders are included.
496 int ProjectFile::GetSubfolders() const
502 * @brief set subfolder.
503 * @param [in] iSubfolder New value for subfolder inclusion.
505 void ProjectFile::SetSubfolders(int iSubfolder)
507 m_subfolders = iSubfolder ? 1 : 0;