#include "DocTypes.h" NAMESPACE_UPP int QtfParser::GetNumber() { int n = 0; int sgn = 1; if(*term == '-') { sgn = -1; term++; } while(IsDigit(*term)) n = n * 10 + *term++ - '0'; return sgn * n; } String QtfParser::GetString() { String s; for(;;) { if(*term == '\0') return s; if(*term == '^') { term++; return s; } s.Cat(*term++); } } Paragraph& QtfParser::Par() { return table.GetRows() ? table.LastCell() : paragraph; } void QtfParser::Flush(String& text) { if(text.GetLength()) { Par().SetParaFont(state.font); if(state.type == NORMAL) Par().Cat(text, state.font, state.color, state.value); else { Font f = state.font; int h = f.GetHeight(); f.Height(2 * h / 3); Par().Cat(text, f, state.color, state.value, state.type == SUPERSCRIPT ? -abs(h / 3) : abs(h / 5)); } paragraph.SetStyle(state); } text.Clear(); } Color QtfParser::GetColor() { static Color color[] = { Black, LtGray, White, Red, Green, Blue, LtRed, WhiteGray, LtCyan, Yellow }; int c = *term++; if(c == '(') { byte r = GetNumber(); if(Key(')')) { r &= 255; return Color(r, r, r); } Key('.'); byte g = GetNumber(); Key('.'); byte b = GetNumber(); Key(')'); return Color(r, g, b); } else if(c >= '0' && c <= '9') return color[c - '0']; else return Red; } void QtfParser::Picture(int type) { int cx = 0; int cy = 0; term++; cx = GetNumber(); Key(':'); cy = GetNumber(); Key(' '); String name; while(*term != ']' && *term) name.Cat(*term++); if(type == 0) { #ifdef PLATFORM_WIN32 Drawing iw = Drawing::LoadWMF(GetExeDirFile(name)); if(!iw) iw = Drawing::LoadWMF(name); if(iw) Par().Cat(PaintRect(DrawingDisplay(), iw), cx, cy, state.value); #endif } else if(type == 3) { bool isx = (name.GetLength() == 8); for(const char *p = name; isx && *p; p++) isx = IsXDigit(*p); if(isx) Par().Cat(*(PaintRect *)(strtoul(name, NULL, 16)), cx, cy, state.value); } // else // Par().Cat(type == 1 ? PaintRect(NameNImageDisplay(), name) // : PaintRect(NameSImageDisplay(), name), cx, cy, state.value); if(*term) term++; } void QtfParser::Celln(int& a, int& b) { a = -1; b = -1; if(IsDigit(*term)) a = GetNumber(); if(*term == '/') { term++; b = GetNumber(); } } QtfParser::Code QtfParser::Error(const char *s) { paragraph.Clear(); paragraph.Cat("ERROR: " + String(s) + ": " + String(term, min(strlen(term), 20)), Arial(84).Bold().Underline(), Red); term = ""; return PARAGRAPH; } QtfParser::Code QtfParser::Parse() { String text; paragraph.Clear(); table.Clear(); if(*term == '\0') { paragraph.SetStyle(state); paragraph.SetParaFont(state.font); Code e = ender; ender = END; return e; } ender = END; if(inraw) goto toinraw; while(Key(']')) if(stack.GetCount()) { state = stack.Top(); stack.Drop(); } else return Error("[ UNMATCHED"); if(Key2('^') || Key('\f')) return PAGE; if(Key2('+')) { table.AddRow(); table.AddCell(); } Par().SetStyle(state); for(;;) { if(*term == '\0') { Flush(text); return IsTable() ? TABLE : PARAGRAPH; } if(Term2('^') || *term == '\f') { Flush(text); return IsTable() ? TABLE : PARAGRAPH; } if(Term2('+')) { Flush(text); if(IsTable()) { term += 2; return TABLE; } else return PARAGRAPH; } if(Key('\n') || Key('&')) { Flush(text); Par().SetParaFont(state.font); if(!IsTable()) { ender = *term ? PARAGRAPH : END; return PARAGRAPH; } Cell().NewPar(); Par().SetStyle(state); continue; } if(Key('\t') || Key2('|')) { Flush(text); if(!IsTable()) return PARAGRAPH; table.AddCell(); continue; } if(Key('\v') || Key2('-')) { Flush(text); if(!IsTable()) return PARAGRAPH; table.AddRow(); table.AddCell(); continue; } if(Key('`') || Key('\\')) { text.Cat(*term++); continue; } if(Key2(':')) { Flush(text); if(!IsTable()) return Error("NOT IN TABLE"); while(*term != ' ' && *term != '\n') { int a, b; switch(*term++) { case 0: return END; case '^': Cell().Top(); break; case '=': Cell().VertCenter(); break; case 'v': Cell().Bottom(); break; case 'l': Celln(a, b); if(a >= 0) Cell().LeftWidth(a); if(b >= 0) Cell().LeftSpace(b); break; case 'r': Celln(a, b); if(a >= 0) Cell().RightWidth(a); if(b >= 0) Cell().RightSpace(b); break; case 't': Celln(a, b); if(a >= 0) Cell().TopWidth(a); if(b >= 0) Cell().TopSpace(b); break; case 'b': Celln(a, b); if(a >= 0) Cell().BottomWidth(a); if(b >= 0) Cell().BottomSpace(b); break; case 'a': Celln(a, b); if(a >= 0) Cell().FrameWidth(a); if(b >= 0) Cell().FrameSpace(b); break; case '@': Cell().Paper(GetColor()); break; case '<': table.Lm(GetNumber()); break; case '>': table.Rm(GetNumber()); break; case 'f': table.FrameWidth(GetNumber()); break; case 'h': table.HeaderRows(GetNumber()); break; case '_': table.FrameColor(GetColor()); break; case 's': table.Before(GetNumber()); break; case '!': Cell().Clear(); break; case '~': Cell().FrameWidth(0); table.FrameWidth(0); break; case '/': Cell().Keep(); break; case '+': Cell().Span(GetNumber()); break; default: term--; if(IsDigit(*term)) Cell().Ratio(GetNumber()); else term++; } } term++; continue; } if(Key('[')) { Flush(text); if(*term == 'P') Picture(0); else if(*term == 'I') Picture(1); else if(*term == 'J') Picture(2); else if(*term == 'K') Picture(3); else { stack.Add(state); for(;;) { int c = *term++; if(c == ' ' || c == '\n') break; switch(c) { case 0: return END; case '[': stack.Add(state); break; case '/': state.font.Italic(!state.font.IsItalic()); break; case '_': state.font.Underline(!state.font.IsUnderline()); break; case '*': state.font.Bold(!state.font.IsBold()); break; case '-': state.font.Strikeout(!state.font.IsStrikeout()); break; case '`': state.type = SUPERSCRIPT; break; case ',': state.type = SUBSCRIPT; break; case 'A': state.font = state.font.Face(Font::ARIAL); break; case 'R': state.font = state.font.Face(Font::ROMAN); break; case 'C': state.font = state.font.Face(Font::COURIER); break; case 'G': state.font = state.font.Face(Font::STDFONT); break; case 'S': state.font = state.font.Face(Font::SYMBOL); break; #ifdef PLATFORM_WIN32 case 'W': state.font = state.font.Face(Font::WINGDINGS); break; #endif case '.': state.font = state.font.Face(GetNumber()); break; case '^': state.value = GetString(); break; case '<': Par().Left(); state.align = ALIGN_LEFT; break; case '>': Par().Right(); state.align = ALIGN_RIGHT; break; case '=': Par().Center(); state.align = ALIGN_CENTER; break; case '#': Par().Justify(); state.align = ALIGN_JUSTIFY; break; case 'l': Par().Lm(state.lm = GetNumber()); break; case 'r': Par().Rm(state.rm = GetNumber()); break; case 'i': Par().Indent(state.indent = GetNumber()); break; case 'b': Par().Before(state.before = GetNumber()); break; case 'a': Par().After(state.after = GetNumber()); break; case 'o': Par().Bullet(); state.bullet = Paragraph::StdBullet(); state.bulletindent = 150; break; case 'O': { int a, b; Celln(a, b); state.bullet = a == 1 ? Paragraph::WhiteBullet() : a == 2 ? Paragraph::BoxBullet() : a == 3 ? Paragraph::WhiteBoxBullet() : Paragraph::StdBullet(), state.bulletindent = b < 0 ? 150 : b; Par().Bullet(state.bullet, state.bulletindent); } break; case '!': { String fn; for(;;) { if(*term == '!') { term++; break; } if(*term == '\0') break; fn.Cat(*term++); } state.font.Face(Font::FindFaceNameIndex(fn)); } break; case '+': state.font.Height(GetNumber()); break; case '@': state.color = GetColor(); break; default: if(c >= '0' && c <= '9') { static int fsize[] = { 50, 67, 84, 100, 134, 167, 200, 234, 300, 400 }; state.font.Height(fsize[c - '0']); } break; } } } } else if(Key(']')) { Flush(text); if(stack.GetCount()) { state = stack.Top(); stack.Drop(); } } else if(*term == '_') { text.Cat(31); term++; } else if(*term == '\1') { term++; toinraw: for(;;) { if(*term == '\0') break; if(*term == '\1') { inraw = false; term++; break; } if(*term == '\n' && !IsTable()) { inraw = true; term++; Flush(text); ender = PARAGRAPH; return PARAGRAPH; } text.Cat(*term++); } } else if((byte)*term >= 31) text.Cat(*term++); else term++; } String spc(" "); Flush(spc); } void QtfParser::Init() { state.font = Arial(-84); state.color = Black; state.Init(); charset = 0; ender = END; } END_UPP_NAMESPACE