ultimatepp/uppsrc/DocTypes/QtfEncoder.cpp
mdelfede d2b54f7989 changed svn layout
git-svn-id: svn://ultimatepp.org/upp/trunk@281 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-06-07 22:31:27 +00:00

263 lines
6.4 KiB
C++

#include "DocTypes.h"
NAMESPACE_UPP
static Color DocQTFColor[] = {
Black, LtGray, White, Red, Green, Blue, LtRed, WhiteGray, LtCyan, Yellow
};
static int DocQTFFontHeight[] = {
50, 67, 84, 100, 134, 167, 200, 234, 300, 400
};
static void SeparateNumber(String& s)
{
if(*s.Last() >= '0' && *s.Last() <= '9')
s.Cat(';');
}
//////////////////////////////////////////////////////////////////////
struct RichObjectTypeDrawingData
{
void Serialize(Stream& stream);
Drawing drawing;
Size dot_size;
String comment;
};
void RichObjectTypeDrawingData::Serialize(Stream& stream)
{
int version = 1;
stream % version % dot_size % comment % drawing;
}
static String RichObjectTypeDrawingTypeName()
{
return "Drawing";
}
static String FmtColor(Color c)
{
if(IsNull(c)) return "N";
for(int i = 0; i < 10; i++)
if(DocQTFColor[i] == c)
return String(i + '0', 1);
return NFormat("(%d.%d.%d)", c.GetR(), c.GetG(), c.GetB());
}
String CharFmt(const Paragraph::Part& a, const Paragraph::Part& b)
{
String fmt;
if(a.font.IsBold() != b.font.IsBold()) fmt.Cat('*');
if(a.font.IsItalic() != b.font.IsItalic()) fmt.Cat('/');
if(a.font.IsUnderline() != b.font.IsUnderline()) fmt.Cat('_');
if(a.font.IsStrikeout() != b.font.IsStrikeout()) fmt.Cat('-');
// if(a.capitals != b.capitals) fmt.Cat('c');
if(a.delta != b.delta)
fmt.Cat(b.delta == 0 ? a.delta < 0 ? '`' : ',' :
b.delta < 0 ? '`' : ',');
if(a.font.GetFace() != b.font.GetFace())
switch(b.font.GetFace()) {
case Font::ARIAL: fmt.Cat('A'); break;
case Font::ROMAN: fmt.Cat('R'); break;
case Font::COURIER: fmt.Cat('C'); break;
case Font::STDFONT: fmt.Cat('G'); break;
case Font::SYMBOL: fmt.Cat('S'); break;
default:
fmt << "!" << a.font.GetFaceName() << "!";
}
if(a.value != b.value)
fmt << '^' << DeQtf(StdFormat(b.value)) << '^';
if(a.color != b.color)
fmt << "@" << FmtColor(b.color);
if(a.font.GetHeight() != b.font.GetHeight()) {
for(int i = 0; i < 10; i++)
if(b.font.GetHeight() == DocQTFFontHeight[i]) {
SeparateNumber(fmt);
fmt.Cat('0' + i);
return fmt;
}
fmt.Cat(NFormat("+%d", tabs(b.font.GetHeight())));
}
return fmt;
}
static String sFmtNumber(char c, int former, int current)
{
return former != current ? NFormat("%c%d", c, current) : String();
}
String QTFEncodeParaFormat(const Paragraph::Style& format, const Paragraph::Part& charformat,
const Paragraph::Style& style, const Paragraph::Part& charstyle,
bool savecharformat)
{
String qtf;
if(format.align != style.align)
switch(format.align) {
case ALIGN_LEFT: qtf << '<'; break;
case ALIGN_RIGHT: qtf << '>'; break;
case ALIGN_CENTER: qtf << '='; break;
case ALIGN_JUSTIFY: qtf << '#'; break;
}
qtf << sFmtNumber('l', style.lm, format.lm)
<< sFmtNumber('r', style.rm, format.rm)
<< sFmtNumber('i', style.indent, format.indent)
<< sFmtNumber('b', style.before, format.before)
<< sFmtNumber('a', style.after, format.after);
if(style.bullet != format.bullet) {
qtf << 'O';
qtf << (format.bullet ? "0" : "_");
}
if(savecharformat)
qtf << CharFmt(charstyle, charformat);
qtf << " ";
return qtf;
}
String QTFEncodePara(const Paragraph& p,
const Paragraph::Style& style, const Paragraph::Part& charstyle)
{
Paragraph::Part paraformat;
paraformat.font = p.GetParaFont();
String qtf = QTFEncodeParaFormat(p.GetStyle(), paraformat, style, charstyle,
p.GetCount() == 0);
int d = qtf.GetLength();
for(int i = 0; i < p.GetCount(); i++) {
const Paragraph::Part& part = p.GetParts()[i];
if(part.pr) {
// const RichObject& object = part.object;
Size sz = part.sz;
qtf << "\r\n";
qtf << "@@" << RichObjectTypeDrawingTypeName() << ':' << sz.cx
<< '*' << sz.cy << "\r\n";
DrawingDraw ddraw(sz);
part.pr.Paint(ddraw, sz, Black, White, 0);
RichObjectTypeDrawingData dwg;
dwg.drawing = ddraw;
dwg.dot_size = sz;
StringStream datastrm;
datastrm % dwg;
String data = datastrm;
const char *q = data.Begin();
const char *slim = data.End();
int n = 0;
qtf.Reserve(qtf.GetLength() + 8 * data.GetLength() / 7);
while(q < slim - 7) {
byte seven = 0;
byte data[8];
data[0] = ((q[0] & 0x80) >> 7) |
((q[1] & 0x80) >> 6) |
((q[2] & 0x80) >> 5) |
((q[3] & 0x80) >> 4) |
((q[4] & 0x80) >> 3) |
((q[5] & 0x80) >> 2) |
((q[6] & 0x80) >> 1) |
0x80;
data[1] = q[0] | 0x80;
data[2] = q[1] | 0x80;
data[3] = q[2] | 0x80;
data[4] = q[3] | 0x80;
data[5] = q[4] | 0x80;
data[6] = q[5] | 0x80;
data[7] = q[6] | 0x80;
qtf.Cat(data, 8);
if(++n % 10 == 0)
qtf << "\r\n";
q += 7;
}
while(q < slim) {
byte seven = 0;
const char *lim = slim;
const char *s;
for(s = q; s < lim; s++)
seven = (seven >> 1) | (*s & 0x80);
seven >>= 8 - (lim - q);
qtf.Cat(seven | 0x80);
for(s = q; s < lim; s++)
qtf.Cat(*s | 0x80);
if(++n % 10 == 0)
qtf << "\r\n";
q += 7;
}
}
else {
String cf = CharFmt(charstyle, part);
if(!cf.IsEmpty()) {
qtf << '[' << cf << ' ';
d += cf.GetLength() + 2;
}
for(const char *s = part.text.Begin(); s != part.text.End(); s++) {
byte c = *s;
if(c < 128) {
if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'
|| c == ' ' || c == '.' || c == ',' || c == '?' || c == '(' || c == ')'
|| c == ';')
{
qtf.Cat(c);
d++;
}
else if(c == 9)
{
qtf.Cat(127);
d++;
}
else if(c == 31)
{
qtf.Cat('_');
d++;
}
else
{
qtf.Cat('`');
qtf.Cat(c);
d += 2;
}
if(d > 60 && c == ' ')
{
qtf.Cat("\r\n");
d = 0;
}
}
else
{
qtf.Cat(c);
d++;
}
if(d > 80)
{
qtf.Cat("\r\n");
d = 0;
}
}
if(!cf.IsEmpty()) {
d++;
qtf << ']';
}
}
}
return qtf;
}
String AsQtf(const Document& text)
{
Paragraph::Style empty_format;
empty_format.Init();
Paragraph::Part empty_part;
String qtf;
// qtf << "[";
for(int i = 0; i < text.GetCount(); i++)
if(text.IsParagraph(i)) {
const Paragraph& p = text.GetParagraph(i);
if(i) qtf << "\r\n&\r\n";
qtf << "[";
qtf << QTFEncodePara(p, empty_format, empty_part);
qtf << "]";
}
qtf << "\r\n"; // ]";
return qtf;
}
END_UPP_NAMESPACE