mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
262 lines
6.4 KiB
C++
262 lines
6.4 KiB
C++
#include <precomp.h>
|
|
|
|
#include "xmlwrite.h"
|
|
|
|
#include <bfc/wasabi_std.h>
|
|
#include <bfc/string/bfcstring.h>
|
|
#include <bfc/parse/paramparser.h>
|
|
|
|
#if 0
|
|
static unsigned char xmltypecheck[256] =
|
|
{
|
|
#define BT_COLON BT_NMSTRT
|
|
#include "latin1tab.h"
|
|
#undef BT_COLON
|
|
#include "asciitab.h"
|
|
};
|
|
#endif
|
|
|
|
#define EFPRINTF (nohicharconversion ? eutf8fprintf : efprintf)
|
|
|
|
#include "../nu/AutoChar.h"
|
|
XMLWrite::XMLWrite(const wchar_t *filename, const wchar_t *doctype, const wchar_t *dtddoctype, int no_hi_chars_conversion)
|
|
{
|
|
nohicharconversion = no_hi_chars_conversion;
|
|
FILE *f = _wfopen(filename, WF_WRITE_BINARY);
|
|
Init(f, doctype, dtddoctype);
|
|
}
|
|
|
|
XMLWrite::XMLWrite(FILE *file, const wchar_t *doctype, const wchar_t *dtddoctype, int no_hi_chars_conversion)
|
|
{
|
|
nohicharconversion = no_hi_chars_conversion;
|
|
Init(file, doctype, dtddoctype);
|
|
}
|
|
|
|
void XMLWrite::Init(FILE *file, const wchar_t *doctype, const wchar_t *dtddoctype)
|
|
{
|
|
fp = file;
|
|
ASSERT(fp != NULL); // sheet, need exceptions here
|
|
indenter.setValue(L"");
|
|
utf8fprintf(fp, L"<?xml version=\"1.0\" encoding='UTF-8' standalone=\"yes\"?>\n");
|
|
if (dtddoctype != NULL)
|
|
utf8fprintf(fp, L"<!DOCTYPE %s>\n", dtddoctype);
|
|
pushCategory(doctype, 1, 0);
|
|
}
|
|
|
|
XMLWrite::~XMLWrite()
|
|
{
|
|
popCategory(1, 0);
|
|
fflush(fp);
|
|
fclose(fp);
|
|
ASSERT(titles.peek() == 0);
|
|
}
|
|
|
|
void XMLWrite::comment(const wchar_t *comment)
|
|
{
|
|
utf8fprintf(fp, L"<!-- %s -->\n", comment);
|
|
}
|
|
|
|
void XMLWrite::pushCategory(const wchar_t *title, int wantcr, int wantindent)
|
|
{
|
|
if (wantindent)
|
|
{
|
|
utf8fprintf(fp, L"%s<%s>%s", indenter.getValue(), title, wantcr ? L"\n" : L"");
|
|
}
|
|
else
|
|
utf8fprintf(fp, L"<%s>%s", title, wantcr ? L"\n" : L"");
|
|
indenter+=L" ";
|
|
ParamParser pp(title, L" ");
|
|
titles.push(WCSDUP(pp.enumItem(0)));
|
|
}
|
|
|
|
void XMLWrite::pushCategoryAttrib(const wchar_t *title, int nodata)
|
|
{
|
|
utf8fprintf(fp, L"%s<%s", indenter.getValue(), title);
|
|
indenter+=L" ";
|
|
titles.push(nodata ? NULL : WCSDUP(title));
|
|
}
|
|
|
|
void XMLWrite::writeCategoryAttrib(const wchar_t *title, const int val)
|
|
{
|
|
utf8fprintf(fp, L" %s=\"%d\"", title, val);
|
|
}
|
|
|
|
void XMLWrite::writeCategoryAttrib(const wchar_t *title, const wchar_t *str)
|
|
{
|
|
if (!str)
|
|
str = L"";
|
|
utf8fprintf(fp, L" %s=\"", title);
|
|
EFPRINTF(fp, L"%s", str);
|
|
utf8fprintf(fp, L"\"");
|
|
}
|
|
|
|
void XMLWrite::closeCategoryAttrib(int wantcr)
|
|
{
|
|
if (titles.top() == NULL)
|
|
utf8fprintf(fp, L" /");
|
|
utf8fprintf(fp, L">%s", wantcr ? L"\n" : L"");
|
|
}
|
|
|
|
void XMLWrite::writeAttribEmpty(const wchar_t *title, int wantcr, int wantindent)
|
|
{
|
|
if (wantindent)
|
|
utf8fprintf(fp, L"%s<%s/>%s", indenter.getValue(), title, wantcr ? L"\n" : L"");
|
|
else
|
|
utf8fprintf(fp, L"<%s/>%s", title, wantcr ? L"\n" : L"");
|
|
}
|
|
|
|
void XMLWrite::writeAttrib(const wchar_t *title, const wchar_t *text, int wantcr, int wantindent)
|
|
{
|
|
if (text && *text)
|
|
{
|
|
if (wantindent)
|
|
utf8fprintf(fp, L"%s<%s>", indenter.getValue(), title);
|
|
else
|
|
utf8fprintf(fp, L"<%s>", title);
|
|
EFPRINTF(fp, L"%s", text);
|
|
utf8fprintf(fp, L"</%s>%s", title, wantcr ? L"\n" : L"");
|
|
}
|
|
else
|
|
{
|
|
writeAttribEmpty(title, wantcr, wantindent);
|
|
}
|
|
}
|
|
|
|
void XMLWrite::writeAttrib(const wchar_t *title, int val, int wantcr, int wantindent)
|
|
{
|
|
if (wantindent)
|
|
utf8fprintf(fp, L"%s<%s>%d</%s>%s", indenter.getValue(), title, val, title, wantcr ? L"\n" : L"");
|
|
else
|
|
utf8fprintf(fp, L"<%s>%d</%s>%s", title, val, title, wantcr ? L"\n" : L"");
|
|
}
|
|
|
|
int XMLWrite::popCategory(int wantcr, int wantindent)
|
|
{
|
|
indenter.trunc(-2);
|
|
wchar_t *title;
|
|
int r = titles.pop(&title);
|
|
if (!r) return 0;
|
|
if (title != NULL)
|
|
{
|
|
if (wantindent)
|
|
utf8fprintf(fp, L"%s</%s>%s", indenter.getValue(), title, wantcr ? L"\n" : L"");
|
|
else
|
|
utf8fprintf(fp, L"</%s>%s", title, wantcr ? L"\n" : L"");
|
|
FREE(title);
|
|
}
|
|
return titles.peek();
|
|
}
|
|
|
|
int XMLWrite::utf8fprintf(FILE *fp, const wchar_t *format, ...)
|
|
{
|
|
va_list v;
|
|
StringW outstr;
|
|
va_start(v, format);
|
|
outstr.va_sprintf(format, v);
|
|
va_end(v);
|
|
|
|
#ifdef _WIN32
|
|
AutoChar utf8(outstr, CP_UTF8);
|
|
#else
|
|
#warning port me
|
|
AutoChar utf8(outstr);
|
|
#endif
|
|
const char *data = (const char *)utf8; // to make the next line less messay
|
|
fwrite(data, STRLEN(data), 1, fp);
|
|
return 0;
|
|
}
|
|
|
|
int XMLWrite::eutf8fprintf(FILE *fp, const wchar_t *format, ...)
|
|
{
|
|
va_list v;
|
|
StringW outstr;
|
|
va_start(v, format);
|
|
outstr.va_sprintf(format, v);
|
|
va_end(v);
|
|
|
|
#ifdef _WIN32
|
|
AutoChar utf8(outstr, CP_UTF8);
|
|
#else
|
|
#warning port me
|
|
AutoChar utf8(outstr);
|
|
#endif
|
|
|
|
const char *data = (const char *)utf8; // to make the next line less messay
|
|
while (data && *data)
|
|
{
|
|
size_t cur_length=0;
|
|
while (data[cur_length] && data[cur_length] != '<' && data[cur_length] != '>' && data[cur_length] != '&' && data[cur_length] != '\"' && data[cur_length] != '\'')
|
|
{
|
|
cur_length++;
|
|
}
|
|
fwrite(data, cur_length, 1, fp);
|
|
data += cur_length;
|
|
if (*data)
|
|
{
|
|
// if we get here, it was a special character
|
|
switch(*data)
|
|
{
|
|
case '<': fwrite("<", 4, 1, fp); break;
|
|
case '>': fwrite(">", 4, 1, fp); break;
|
|
case '&': fwrite("&", 5, 1, fp); break;
|
|
case '\"': fwrite(""", 6, 1, fp); break;
|
|
case '\'': fwrite("'", 6, 1, fp); break;
|
|
}
|
|
data++;
|
|
}
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
int XMLWrite::efprintf(FILE *fp, const wchar_t *format, ...)
|
|
{
|
|
va_list v;
|
|
// http://www.w3.org/TR/REC-xml#syntax
|
|
int bcount = 0;
|
|
StringW outstr;
|
|
va_start(v, format);
|
|
outstr.va_sprintf(format, v);
|
|
va_end(v);
|
|
size_t n = outstr.len();
|
|
for (size_t i = 0; i != n; i++)
|
|
{
|
|
wchar_t c = outstr.getValue()[i];
|
|
switch (c)
|
|
{
|
|
case '<': fwrite("<", 4, 1, fp); bcount += 4; break;
|
|
case '>': fwrite(">", 4, 1, fp); bcount += 4; break;
|
|
case '&': fwrite("&", 5, 1, fp); bcount += 5; break;
|
|
case '\"': fwrite(""", 6, 1, fp); bcount += 6; break;
|
|
case '\'': fwrite("'", 6, 1, fp); bcount += 6; break;
|
|
default:
|
|
// if (xmltypecheck[c] != 0)
|
|
{
|
|
// TODO: benski> optimize by scanning for the next character to be escaped (or NULL)
|
|
size_t numChars=1;
|
|
while (1)
|
|
{
|
|
wchar_t check = outstr.getValue()[i+numChars];
|
|
if (check == 0
|
|
|| check == '<'
|
|
|| check == '>'
|
|
|| check == '&'
|
|
|| check == '\''
|
|
|| check == '\"')
|
|
break;
|
|
numChars++;
|
|
}
|
|
const wchar_t *str = outstr.getValue() + i;
|
|
int len = WideCharToMultiByte(CP_UTF8, 0, str, (int)numChars, 0, 0, 0, 0);
|
|
char *utf8 = (char *)malloc(len);
|
|
WideCharToMultiByte(CP_UTF8, 0, str, (int)numChars, utf8, len, 0, 0);
|
|
fwrite(utf8, len, 1, fp);
|
|
free(utf8);
|
|
bcount+=(int)numChars;
|
|
i+=(numChars-1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return bcount;
|
|
}
|