local_file_mgr.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include <cstdlib>
  2. #include <cassert>
  3. #include <sys/stat.h>
  4. #include <ctype.h>
  5. #include <QDir>
  6. #include <QApplication>
  7. #include <QVector>
  8. #include <QDomDocument>
  9. #include <QLocale>
  10. #include <QTextCodec>
  11. #include <algorithm>
  12. #include "LocalFileMng.h"
  13. /* New QtXml based methods */
  14. QString LocalFileMng::readXmlString( QDomNode node , const QString& nodeName, const QString& defaultValue, bool bCanBeEmpty, bool bShouldExists, bool tinyXmlCompatMode)
  15. {
  16. QDomElement element = node.firstChildElement( nodeName );
  17. if( !node.isNull() && !element.isNull() ){
  18. if( !element.text().isEmpty() ){
  19. return element.text();
  20. } else {
  21. if ( !bCanBeEmpty ) {
  22. //_WARNINGLOG( "Using default value in " + nodeName );
  23. }
  24. return defaultValue;
  25. }
  26. } else {
  27. if( bShouldExists ){
  28. //_WARNINGLOG( "'" + nodeName + "' node not found" );
  29. }
  30. return defaultValue;
  31. }
  32. }
  33. float LocalFileMng::readXmlFloat( QDomNode node , const QString& nodeName, float defaultValue, bool bCanBeEmpty, bool bShouldExists, bool tinyXmlCompatMode)
  34. {
  35. QLocale c_locale = QLocale::c();
  36. QDomElement element = node.firstChildElement( nodeName );
  37. if( !node.isNull() && !element.isNull() ){
  38. if( !element.text().isEmpty() ){
  39. return c_locale.toFloat(element.text());
  40. } else {
  41. if ( !bCanBeEmpty ) {
  42. //_WARNINGLOG( "Using default value in " + nodeName );
  43. }
  44. return defaultValue;
  45. }
  46. } else {
  47. if( bShouldExists ){
  48. //_WARNINGLOG( "'" + nodeName + "' node not found" );
  49. }
  50. return defaultValue;
  51. }
  52. }
  53. int LocalFileMng::readXmlInt( QDomNode node , const QString& nodeName, int defaultValue, bool bCanBeEmpty, bool bShouldExists, bool tinyXmlCompatMode)
  54. {
  55. QLocale c_locale = QLocale::c();
  56. QDomElement element = node.firstChildElement( nodeName );
  57. if( !node.isNull() && !element.isNull() ){
  58. if( !element.text().isEmpty() ){
  59. return c_locale.toInt( element.text() );
  60. } else {
  61. if ( !bCanBeEmpty ) {
  62. //_WARNINGLOG( "Using default value in " + nodeName );
  63. }
  64. return defaultValue;
  65. }
  66. } else {
  67. if( bShouldExists ){
  68. //_WARNINGLOG( "'" + nodeName + "' node not found" );
  69. }
  70. return defaultValue;
  71. }
  72. }
  73. bool LocalFileMng::readXmlBool( QDomNode node , const QString& nodeName, bool defaultValue, bool bShouldExists, bool tinyXmlCompatMode)
  74. {
  75. QDomElement element = node.firstChildElement( nodeName );
  76. if( !node.isNull() && !element.isNull() ){
  77. if( !element.text().isEmpty() ){
  78. if( element.text() == "true"){
  79. return true;
  80. } else {
  81. return false;
  82. }
  83. } else {
  84. //_WARNINGLOG( "Using default value in " + nodeName );
  85. return defaultValue;
  86. }
  87. } else {
  88. if( bShouldExists ){
  89. //_WARNINGLOG( "'" + nodeName + "' node not found" );
  90. }
  91. return defaultValue;
  92. }
  93. }
  94. /* Convert (in-place) an XML escape sequence into a literal byte,
  95. * rather than the character it actually refers to.
  96. */
  97. void LocalFileMng::convertFromTinyXMLString( QByteArray* str )
  98. {
  99. /* When TinyXML encountered a non-ASCII character, it would
  100. * simply write the character as "&#xx;" -- where "xx" is
  101. * the hex character code. However, this doesn't respect
  102. * any encodings (e.g. UTF-8, UTF-16). In XML, &#xx; literally
  103. * means "the Unicode character # xx." However, in a UTF-8
  104. * sequence, this could be an escape character that tells
  105. * whether we have a 2, 3, or 4-byte UTF-8 sequence.
  106. *
  107. * For example, the UTF-8 sequence 0xD184 was being written
  108. * by TinyXML as "&#xD1;&#x84;". However, this is the UTF-8
  109. * sequence for the cyrillic small letter EF (which looks
  110. * kind of like a thorn or a greek phi). This letter, in
  111. * XML, should be saved as &#x00000444;, or even literally
  112. * (no escaping). As a consequence, when &#xD1; is read
  113. * by an XML parser, it will be interpreted as capital N
  114. * with a tilde (~). Then &#x84; will be interpreted as
  115. * an unknown or control character.
  116. *
  117. * So, when we know that TinyXML wrote the file, we can
  118. * simply exchange these hex sequences to literal bytes.
  119. */
  120. int pos = 0;
  121. pos = str->indexOf("&#x");
  122. while( pos != -1 ) {
  123. if( isxdigit(str->at(pos+3))
  124. && isxdigit(str->at(pos+4))
  125. && (str->at(pos+5) == ';') ) {
  126. char w1 = str->at(pos+3);
  127. char w2 = str->at(pos+4);
  128. w1 = tolower(w1) - 0x30; // '0' = 0x30
  129. if( w1 > 9 ) w1 -= 0x27; // '9' = 0x39, 'a' = 0x61
  130. w1 = (w1 & 0xF);
  131. w2 = tolower(w2) - 0x30; // '0' = 0x30
  132. if( w2 > 9 ) w2 -= 0x27; // '9' = 0x39, 'a' = 0x61
  133. w2 = (w2 & 0xF);
  134. char ch = (w1 << 4) | w2;
  135. (*str)[pos] = ch;
  136. ++pos;
  137. str->remove(pos, 5);
  138. }
  139. pos = str->indexOf("&#x");
  140. }
  141. }
  142. bool LocalFileMng::checkTinyXMLCompatMode( const QString& filename )
  143. {
  144. /*
  145. Check if filename was created with TinyXml or QtXml
  146. TinyXML: return true
  147. QtXml: return false
  148. */
  149. QFile file( filename );
  150. if ( !file.open(QIODevice::ReadOnly) )
  151. return false;
  152. QString line = file.readLine();
  153. file.close();
  154. if ( line.startsWith( "<?xml" )){
  155. return false;
  156. } else {
  157. //_WARNINGLOG( QString("File '%1' is being read in "
  158. // "TinyXML compatability mode")
  159. // .arg(filename) );
  160. return true;
  161. }
  162. }
  163. QDomDocument LocalFileMng::openXmlDocument( const QString& filename )
  164. {
  165. bool TinyXMLCompat = LocalFileMng::checkTinyXMLCompatMode( filename );
  166. QDomDocument doc;
  167. QFile file( filename );
  168. if ( !file.open(QIODevice::ReadOnly) )
  169. return QDomDocument();
  170. if( TinyXMLCompat ) {
  171. QString enc = QTextCodec::codecForLocale()->name();
  172. if( enc == QString("System") ) {
  173. enc = "UTF-8";
  174. }
  175. QByteArray line;
  176. QByteArray buf = QString("<?xml version='1.0' encoding='%1' ?>\n")
  177. .arg( enc )
  178. .toLocal8Bit();
  179. //_INFOLOG( QString("Using '%1' encoding for TinyXML file").arg(enc) );
  180. while( !file.atEnd() ) {
  181. line = file.readLine();
  182. LocalFileMng::convertFromTinyXMLString( &line );
  183. buf += line;
  184. }
  185. if( ! doc.setContent( buf ) ) {
  186. file.close();
  187. return QDomDocument();
  188. }
  189. } else {
  190. if( ! doc.setContent( &file ) ) {
  191. file.close();
  192. return QDomDocument();
  193. }
  194. }
  195. file.close();
  196. return doc;
  197. }