wp6.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Ariya Hidayat <ariya@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <config.h>
21
22#ifdef HAVE_UNISTD_H
23#include <unistd.h>
24#endif
25
26#include <tqtextcodec.h>
27#include <tqfile.h>
28#include <tqfileinfo.h>
29#include <tqtextstream.h>
30#include <tqvaluevector.h>
31
32#include <KWEFBaseWorker.h>
33#include <KWEFKWordLeader.h>
34#include <KWEFUtil.h>
35
36#include <wp6.h>
37
38bool WPSixWorker::doOpenFile(const TQString& filenameOut, const TQString& /*to*/)
39{
40 filename = filenameOut;
41 outfile.setName( filename );
42 if( !outfile.open( IO_WriteOnly ) )
43 return false;
44
45 output.setDevice( &outfile );
46 output.setByteOrder (TQDataStream::LittleEndian);
47 return true;
48}
49
50bool WPSixWorker::doCloseFile(void)
51{
52 // asssume we're at the end of the file
53 TQ_UINT32 total_filesize = outfile.at();
54
55 // close the file first
56 outfile.close();
57
58 // reopen for read and write
59 if( !outfile.open( IO_ReadWrite ) )
60 return false;
61 output.setDevice( &outfile );
62
63 // now it's time to fix-up some header fields
64
65 // fix for offset 12, int32, filesize
66 outfile.at( 20 );
67 output << total_filesize;
68
69 // offset 4, int32, pointer to document area
70 outfile.at( 4 );
71 output << document_area_ptr;
72
73 outfile.close();
74 return true;
75}
76
77bool WPSixWorker::doOpenDocument(void)
78{
79 // write WP document header
80 // note that some fields are still "dummy"
81
82 // magic id: -1, "WPC"
83 TQ_UINT8 magic[] = { 0xff, 0x57, 0x50, 0x43 };
84 for( int i=0; i<4; i++ ) output << magic[i];
85
86 // pointer to document area (dummy, will be fixed later)
87 TQ_UINT8 docptr[] = { 0x0E, 0x02, 0x00, 0x00 } ;
88 for( int i=0; i<4; i++ ) output << docptr[i];
89
90 // write product type ( 1 = WordPerfect )
91 TQ_UINT8 product_type = 1;
92 output << product_type;
93
94 // write file type ( 10 = WordPerfect document )
95 TQ_UINT8 file_type = 10;
96 output << file_type;
97
98 // write version (TODO explain)
99 TQ_UINT16 version = 0x0202;
100 output << version;
101
102 // write encryption flag ( 0 = not encrypted )
103 TQ_UINT16 encrypt = 0;
104 output << encrypt;
105
106 // offset to index header (always 0x200?)
107 TQ_UINT16 index_header_ptr = 0x200;
108 output << index_header_ptr;
109
110 // beginning of extended file header (always 5)
111 TQ_UINT32 extheader = 5;
112 output << extheader;
113
114 // filesize (dummy, will be fixed later)
115 TQ_UINT32 filesize = 0;
116 output << filesize;
117
118 // filler 488 bytes
119 TQ_UINT8 dummy = 0;
120 for( int i=0; i<488; i++ ) output << dummy;
121
122 // index header (specified 0 index!)
123 TQ_UINT8 index_header[] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
124 0, 0, 0, 0 };
125 for( int i=0; i<14; i++ ) output << index_header[i];
126
127 // document area starts, mark it for the header fields
128 document_area_ptr = output.device()->at();
129
130 return true;
131}
132
133bool WPSixWorker::doCloseDocument(void)
134{
135 return true;
136}
137
138// this helper functions "escape" plain Unicode string to WP-compliance string
139// what it does: converting spaces and tabs to hard-spaces and hard-tabs
140// TODO handle Unicode characters using WP charsets
141static TQCString WPSixEscape( const TQString& text )
142{
143 TQCString result;
144
145 for( unsigned int i=0; i < text.length(); i++ )
146 {
147 int c = text[i].unicode();
148 if( c < 32 ) result += '.';
149 else if ( c == 32 ) result += 0x80 ; // hard space
150 else if ( c < 128 ) result += text[i].latin1();
151 else result += '.';
152 }
153
154 return result;
155}
156
157bool WPSixWorker::doFullParagraph(const TQString& paraText,
158 const LayoutData& layout, const ValueListFormatData& paraFormatDataList)
159{
160 // handle paragraph alignment/justification (default to left)
161 unsigned char wp_align[] = { 0xd3, 5, 12, 0, 0, 1, 0, 0, 2, 12, 0, 0xd3 };
162 if( layout.alignment == "left" ) wp_align[7] = 0;
163 if( layout.alignment == "justify" ) wp_align[7] = 1;
164 if( layout.alignment == "center" ) wp_align[7] = 2;
165 if( layout.alignment == "right" ) wp_align[7] = 3;
166 output.writeRawBytes( (const char*)wp_align, 12 );
167
168 ValueListFormatData::ConstIterator it;
169 for( it = paraFormatDataList.begin(); it!=paraFormatDataList.end(); ++it )
170 {
171 const FormatData& formatData = *it;
172
173 // only if the format is for text (id==1)
174 if( formatData.id == 1 )
175 {
176
177 TQ_UINT8 attr = 0; //invalid
178 if( formatData.text.weight >= 75 ) attr = 12; // bold
179 if( formatData.text.italic ) attr = 8;
180 if( formatData.text.underline )
181 {
182 if( formatData.text.underlineValue == "double" )
183 attr = 11; // double underline
184 else
185 attr = 14; // single underline
186 }
187 if( formatData.text.verticalAlignment == 1 ) attr = 6; //subscript
188 if( formatData.text.verticalAlignment == 2 ) attr = 5; //superscript
189 if( formatData.text.strikeout ) attr = 13;
190
191 TQColor fgColor = formatData.text.fgColor;
192 TQColor bgColor = formatData.text.bgColor;
193
194 // due to the file format, before writing the text we must
195 // write some refix-code (such as Bold On) and possibly appropriate suffix-code (Bold Off)
196
197 // attribute on
198 if( attr > 0 ) output << (TQ_UINT8)0xf2 << attr << (TQ_UINT8)0xf2;
199
200 // set font color
201 if( fgColor.isValid() )
202 {
203 TQ_UINT8 wp_color[] = { 0xd4, 0x18, 16, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0xd4 };
204 wp_color[7] = (TQ_UINT8) fgColor.red();
205 wp_color[8] = (TQ_UINT8) fgColor.green();
206 wp_color[9] = (TQ_UINT8) fgColor.blue();
207 output.writeRawBytes( (const char*)wp_color, 16 );
208 }
209
210 // highlight on (background color)
211 if( bgColor.isValid() )
212 {
213 output << (TQ_UINT8) 0xfb;
214 output << (TQ_UINT8)bgColor.red() << (TQ_UINT8)bgColor.green() << (TQ_UINT8)bgColor.blue();
215 output << (TQ_UINT8) 100 << (TQ_UINT8) 0xfb;
216 }
217
218 // the text itself, "escape" it first
219 TQCString out = WPSixEscape( paraText.mid( formatData.pos, formatData.len ) );
220 output.writeRawBytes( (const char*)out, out.length() );
221
222 // attribute off
223 if( attr > 0 ) output << (TQ_UINT8)0xf3 << attr << (TQ_UINT8)0xf3;
224
225 // highlight off
226 if( bgColor.isValid() )
227 {
228 output << (TQ_UINT8) 0xfc;
229 output << (TQ_UINT8)bgColor.red() << (TQ_UINT8)bgColor.green() << (TQ_UINT8)bgColor.blue();
230 output << (TQ_UINT8) 100 << (TQ_UINT8) 0xfc;
231 }
232 }
233
234 }
235
236 // write hard-return
237 output << (TQ_UINT8) 0xcc;
238
239 return true;
240}
241
Paragraph layout.
TQString alignment
left, right, center, justify