xmlwrite.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include <precomp.h>
  2. #include "xmlwrite.h"
  3. #include <bfc/wasabi_std.h>
  4. #include <bfc/string/bfcstring.h>
  5. #include <bfc/parse/paramparser.h>
  6. #if 0
  7. static unsigned char xmltypecheck[256] =
  8. {
  9. #define BT_COLON BT_NMSTRT
  10. #include "latin1tab.h"
  11. #undef BT_COLON
  12. #include "asciitab.h"
  13. };
  14. #endif
  15. #define EFPRINTF (nohicharconversion ? eutf8fprintf : efprintf)
  16. #include "../nu/AutoChar.h"
  17. XMLWrite::XMLWrite(const wchar_t *filename, const wchar_t *doctype, const wchar_t *dtddoctype, int no_hi_chars_conversion)
  18. {
  19. nohicharconversion = no_hi_chars_conversion;
  20. FILE *f = _wfopen(filename, WF_WRITE_BINARY);
  21. Init(f, doctype, dtddoctype);
  22. }
  23. XMLWrite::XMLWrite(FILE *file, const wchar_t *doctype, const wchar_t *dtddoctype, int no_hi_chars_conversion)
  24. {
  25. nohicharconversion = no_hi_chars_conversion;
  26. Init(file, doctype, dtddoctype);
  27. }
  28. void XMLWrite::Init(FILE *file, const wchar_t *doctype, const wchar_t *dtddoctype)
  29. {
  30. fp = file;
  31. ASSERT(fp != NULL); // sheet, need exceptions here
  32. indenter.setValue(L"");
  33. utf8fprintf(fp, L"<?xml version=\"1.0\" encoding='UTF-8' standalone=\"yes\"?>\n");
  34. if (dtddoctype != NULL)
  35. utf8fprintf(fp, L"<!DOCTYPE %s>\n", dtddoctype);
  36. pushCategory(doctype, 1, 0);
  37. }
  38. XMLWrite::~XMLWrite()
  39. {
  40. popCategory(1, 0);
  41. fflush(fp);
  42. fclose(fp);
  43. ASSERT(titles.peek() == 0);
  44. }
  45. void XMLWrite::comment(const wchar_t *comment)
  46. {
  47. utf8fprintf(fp, L"<!-- %s -->\n", comment);
  48. }
  49. void XMLWrite::pushCategory(const wchar_t *title, int wantcr, int wantindent)
  50. {
  51. if (wantindent)
  52. {
  53. utf8fprintf(fp, L"%s<%s>%s", indenter.getValue(), title, wantcr ? L"\n" : L"");
  54. }
  55. else
  56. utf8fprintf(fp, L"<%s>%s", title, wantcr ? L"\n" : L"");
  57. indenter+=L" ";
  58. ParamParser pp(title, L" ");
  59. titles.push(WCSDUP(pp.enumItem(0)));
  60. }
  61. void XMLWrite::pushCategoryAttrib(const wchar_t *title, int nodata)
  62. {
  63. utf8fprintf(fp, L"%s<%s", indenter.getValue(), title);
  64. indenter+=L" ";
  65. titles.push(nodata ? NULL : WCSDUP(title));
  66. }
  67. void XMLWrite::writeCategoryAttrib(const wchar_t *title, const int val)
  68. {
  69. utf8fprintf(fp, L" %s=\"%d\"", title, val);
  70. }
  71. void XMLWrite::writeCategoryAttrib(const wchar_t *title, const wchar_t *str)
  72. {
  73. if (!str)
  74. str = L"";
  75. utf8fprintf(fp, L" %s=\"", title);
  76. EFPRINTF(fp, L"%s", str);
  77. utf8fprintf(fp, L"\"");
  78. }
  79. void XMLWrite::closeCategoryAttrib(int wantcr)
  80. {
  81. if (titles.top() == NULL)
  82. utf8fprintf(fp, L" /");
  83. utf8fprintf(fp, L">%s", wantcr ? L"\n" : L"");
  84. }
  85. void XMLWrite::writeAttribEmpty(const wchar_t *title, int wantcr, int wantindent)
  86. {
  87. if (wantindent)
  88. utf8fprintf(fp, L"%s<%s/>%s", indenter.getValue(), title, wantcr ? L"\n" : L"");
  89. else
  90. utf8fprintf(fp, L"<%s/>%s", title, wantcr ? L"\n" : L"");
  91. }
  92. void XMLWrite::writeAttrib(const wchar_t *title, const wchar_t *text, int wantcr, int wantindent)
  93. {
  94. if (text && *text)
  95. {
  96. if (wantindent)
  97. utf8fprintf(fp, L"%s<%s>", indenter.getValue(), title);
  98. else
  99. utf8fprintf(fp, L"<%s>", title);
  100. EFPRINTF(fp, L"%s", text);
  101. utf8fprintf(fp, L"</%s>%s", title, wantcr ? L"\n" : L"");
  102. }
  103. else
  104. {
  105. writeAttribEmpty(title, wantcr, wantindent);
  106. }
  107. }
  108. void XMLWrite::writeAttrib(const wchar_t *title, int val, int wantcr, int wantindent)
  109. {
  110. if (wantindent)
  111. utf8fprintf(fp, L"%s<%s>%d</%s>%s", indenter.getValue(), title, val, title, wantcr ? L"\n" : L"");
  112. else
  113. utf8fprintf(fp, L"<%s>%d</%s>%s", title, val, title, wantcr ? L"\n" : L"");
  114. }
  115. int XMLWrite::popCategory(int wantcr, int wantindent)
  116. {
  117. indenter.trunc(-2);
  118. wchar_t *title;
  119. int r = titles.pop(&title);
  120. if (!r) return 0;
  121. if (title != NULL)
  122. {
  123. if (wantindent)
  124. utf8fprintf(fp, L"%s</%s>%s", indenter.getValue(), title, wantcr ? L"\n" : L"");
  125. else
  126. utf8fprintf(fp, L"</%s>%s", title, wantcr ? L"\n" : L"");
  127. FREE(title);
  128. }
  129. return titles.peek();
  130. }
  131. int XMLWrite::utf8fprintf(FILE *fp, const wchar_t *format, ...)
  132. {
  133. va_list v;
  134. StringW outstr;
  135. va_start(v, format);
  136. outstr.va_sprintf(format, v);
  137. va_end(v);
  138. #ifdef _WIN32
  139. AutoChar utf8(outstr, CP_UTF8);
  140. #else
  141. #warning port me
  142. AutoChar utf8(outstr);
  143. #endif
  144. const char *data = (const char *)utf8; // to make the next line less messay
  145. fwrite(data, STRLEN(data), 1, fp);
  146. return 0;
  147. }
  148. int XMLWrite::eutf8fprintf(FILE *fp, const wchar_t *format, ...)
  149. {
  150. va_list v;
  151. StringW outstr;
  152. va_start(v, format);
  153. outstr.va_sprintf(format, v);
  154. va_end(v);
  155. #ifdef _WIN32
  156. AutoChar utf8(outstr, CP_UTF8);
  157. #else
  158. #warning port me
  159. AutoChar utf8(outstr);
  160. #endif
  161. const char *data = (const char *)utf8; // to make the next line less messay
  162. while (data && *data)
  163. {
  164. size_t cur_length=0;
  165. while (data[cur_length] && data[cur_length] != '<' && data[cur_length] != '>' && data[cur_length] != '&' && data[cur_length] != '\"' && data[cur_length] != '\'')
  166. {
  167. cur_length++;
  168. }
  169. fwrite(data, cur_length, 1, fp);
  170. data += cur_length;
  171. if (*data)
  172. {
  173. // if we get here, it was a special character
  174. switch(*data)
  175. {
  176. case '<': fwrite("&lt;", 4, 1, fp); break;
  177. case '>': fwrite("&gt;", 4, 1, fp); break;
  178. case '&': fwrite("&amp;", 5, 1, fp); break;
  179. case '\"': fwrite("&quot;", 6, 1, fp); break;
  180. case '\'': fwrite("&apos;", 6, 1, fp); break;
  181. }
  182. data++;
  183. }
  184. };
  185. return 0;
  186. }
  187. int XMLWrite::efprintf(FILE *fp, const wchar_t *format, ...)
  188. {
  189. va_list v;
  190. // http://www.w3.org/TR/REC-xml#syntax
  191. int bcount = 0;
  192. StringW outstr;
  193. va_start(v, format);
  194. outstr.va_sprintf(format, v);
  195. va_end(v);
  196. size_t n = outstr.len();
  197. for (size_t i = 0; i != n; i++)
  198. {
  199. wchar_t c = outstr.getValue()[i];
  200. switch (c)
  201. {
  202. case '<': fwrite("&lt;", 4, 1, fp); bcount += 4; break;
  203. case '>': fwrite("&gt;", 4, 1, fp); bcount += 4; break;
  204. case '&': fwrite("&amp;", 5, 1, fp); bcount += 5; break;
  205. case '\"': fwrite("&quot;", 6, 1, fp); bcount += 6; break;
  206. case '\'': fwrite("&apos;", 6, 1, fp); bcount += 6; break;
  207. default:
  208. // if (xmltypecheck[c] != 0)
  209. {
  210. // TODO: benski> optimize by scanning for the next character to be escaped (or NULL)
  211. size_t numChars=1;
  212. while (1)
  213. {
  214. wchar_t check = outstr.getValue()[i+numChars];
  215. if (check == 0
  216. || check == '<'
  217. || check == '>'
  218. || check == '&'
  219. || check == '\''
  220. || check == '\"')
  221. break;
  222. numChars++;
  223. }
  224. const wchar_t *str = outstr.getValue() + i;
  225. int len = WideCharToMultiByte(CP_UTF8, 0, str, (int)numChars, 0, 0, 0, 0);
  226. char *utf8 = (char *)malloc(len);
  227. WideCharToMultiByte(CP_UTF8, 0, str, (int)numChars, utf8, len, 0, 0);
  228. fwrite(utf8, len, 1, fp);
  229. free(utf8);
  230. bcount+=(int)numChars;
  231. i+=(numChars-1);
  232. }
  233. break;
  234. }
  235. }
  236. return bcount;
  237. }