001/*
002 * $Id: DocWriter.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text;
045
046import java.io.BufferedOutputStream;
047import java.io.IOException;
048import java.io.OutputStream;
049import java.util.Iterator;
050import java.util.Properties;
051
052import com.itextpdf.text.pdf.OutputStreamCounter;
053
054/**
055 * An abstract <CODE>Writer</CODE> class for documents.
056 * <P>
057 * <CODE>DocWriter</CODE> is the abstract class of several writers such
058 * as <CODE>PdfWriter</CODE> and <CODE>HtmlWriter</CODE>.
059 * A <CODE>DocWriter</CODE> can be added as a <CODE>DocListener</CODE>
060 * to a certain <CODE>Document</CODE> by getting an instance (see method
061 * <CODE>getInstance()</CODE> in the specific writer-classes).
062 * Every <CODE>Element</CODE> added to the original <CODE>Document</CODE>
063 * will be written to the <CODE>OutputStream</CODE> of the listening
064 * <CODE>DocWriter</CODE>.
065 *
066 * @see   Document
067 * @see   DocListener
068 */
069
070public abstract class DocWriter implements DocListener {
071
072/** This is some byte that is often used. */
073    public static final byte NEWLINE = (byte)'\n';
074
075/** This is some byte that is often used. */
076    public static final byte TAB = (byte)'\t';
077
078/** This is some byte that is often used. */
079    public static final byte LT = (byte)'<';
080
081/** This is some byte that is often used. */
082    public static final byte SPACE = (byte)' ';
083
084/** This is some byte that is often used. */
085    public static final byte EQUALS = (byte)'=';
086
087/** This is some byte that is often used. */
088    public static final byte QUOTE = (byte)'\"';
089
090/** This is some byte that is often used. */
091    public static final byte GT = (byte)'>';
092
093/** This is some byte that is often used. */
094    public static final byte FORWARD = (byte)'/';
095
096    // membervariables
097
098/** The pageSize. */
099    protected Rectangle pageSize;
100
101/** This is the document that has to be written. */
102    protected Document document;
103
104/** The outputstream of this writer. */
105    protected OutputStreamCounter os;
106
107/** Is the writer open for writing? */
108    protected boolean open = false;
109
110/** Do we have to pause all writing actions? */
111    protected boolean pause = false;
112
113/** Closes the stream on document close */
114    protected boolean closeStream = true;
115
116    // constructor
117
118    protected DocWriter()  {
119    }
120
121/**
122 * Constructs a <CODE>DocWriter</CODE>.
123 *
124 * @param document  The <CODE>Document</CODE> that has to be written
125 * @param os  The <CODE>OutputStream</CODE> the writer has to write to.
126 */
127
128    protected DocWriter(Document document, OutputStream os)  {
129        this.document = document;
130        this.os = new OutputStreamCounter(new BufferedOutputStream(os));
131    }
132
133    // implementation of the DocListener methods
134
135/**
136 * Signals that an <CODE>Element</CODE> was added to the <CODE>Document</CODE>.
137 * <P>
138 * This method should be overridden in the specific <CODE>DocWriter<CODE> classes
139 * derived from this abstract class.
140 *
141 * @param element A high level object to add
142 * @return  <CODE>false</CODE>
143 * @throws  DocumentException when a document isn't open yet, or has been closed
144 */
145
146    public boolean add(Element element) throws DocumentException {
147        return false;
148    }
149
150/**
151 * Signals that the <CODE>Document</CODE> was opened.
152 */
153
154    public void open() {
155        open = true;
156    }
157
158/**
159 * Sets the pagesize.
160 *
161 * @param pageSize  the new pagesize
162 * @return  a <CODE>boolean</CODE>
163 */
164
165    public boolean setPageSize(Rectangle pageSize) {
166        this.pageSize = pageSize;
167        return true;
168    }
169
170/**
171 * Sets the margins.
172 * <P>
173 * This does nothing. Has to be overridden if needed.
174 *
175 * @param marginLeft    the margin on the left
176 * @param marginRight   the margin on the right
177 * @param marginTop   the margin on the top
178 * @param marginBottom  the margin on the bottom
179 * @return  <CODE>false</CODE>
180 */
181
182    public boolean setMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) {
183        return false;
184    }
185
186/**
187 * Signals that an new page has to be started.
188 * <P>
189 * This does nothing. Has to be overridden if needed.
190 *
191 * @return  <CODE>true</CODE> if the page was added, <CODE>false</CODE> if not.
192 */
193
194    public boolean newPage() {
195        if (!open) {
196            return false;
197        }
198        return true;
199    }
200
201/**
202 * Sets the page number to 0.
203 * <P>
204 * This method should be overridden in the specific <CODE>DocWriter<CODE> classes
205 * derived from this abstract class if they actually support the use of
206 * pagenumbers.
207 */
208
209    public void resetPageCount() {
210    }
211
212/**
213 * Sets the page number.
214 * <P>
215 * This method should be overridden in the specific <CODE>DocWriter<CODE> classes
216 * derived from this abstract class if they actually support the use of
217 * pagenumbers.
218 *
219 * @param pageN   the new page number
220 */
221
222    public void setPageCount(int pageN) {
223    }
224
225/**
226 * Signals that the <CODE>Document</CODE> was closed and that no other
227 * <CODE>Elements</CODE> will be added.
228 */
229
230    public void close() {
231        open = false;
232        try {
233            os.flush();
234            if (closeStream)
235                os.close();
236        }
237        catch(IOException ioe) {
238            throw new ExceptionConverter(ioe);
239        }
240    }
241
242    // methods
243
244/** Converts a <CODE>String</CODE> into a <CODE>Byte</CODE> array
245 * according to the ISO-8859-1 codepage.
246 * @param text the text to be converted
247 * @return the conversion result
248 */
249
250    public static final byte[] getISOBytes(String text)
251    {
252        if (text == null)
253            return null;
254        int len = text.length();
255        byte b[] = new byte[len];
256        for (int k = 0; k < len; ++k)
257            b[k] = (byte)text.charAt(k);
258        return b;
259    }
260
261/**
262 * Let the writer know that all writing has to be paused.
263 */
264
265    public void pause() {
266        pause = true;
267    }
268
269    /**
270     * Checks if writing is paused.
271     *
272     * @return          <CODE>true</CODE> if writing temporarily has to be paused, <CODE>false</CODE> otherwise.
273     */
274
275    public boolean isPaused() {
276        return pause;
277    }
278
279/**
280 * Let the writer know that writing may be resumed.
281 */
282
283    public void resume() {
284        pause = false;
285    }
286
287/**
288 * Flushes the <CODE>BufferedOutputStream</CODE>.
289 */
290
291    public void flush() {
292        try {
293            os.flush();
294        }
295        catch(IOException ioe) {
296            throw new ExceptionConverter(ioe);
297        }
298    }
299
300/**
301 * Writes a <CODE>String</CODE> to the <CODE>OutputStream</CODE>.
302 *
303 * @param string    the <CODE>String</CODE> to write
304 * @throws IOException
305 */
306
307    protected void write(String string) throws IOException {
308        os.write(getISOBytes(string));
309    }
310
311/**
312 * Writes a number of tabs.
313 *
314 * @param   indent  the number of tabs to add
315 * @throws IOException
316 */
317
318    protected void addTabs(int indent) throws IOException {
319        os.write(NEWLINE);
320        for (int i = 0; i < indent; i++) {
321            os.write(TAB);
322        }
323    }
324
325/**
326 * Writes a key-value pair to the outputstream.
327 *
328 * @param   key     the name of an attribute
329 * @param   value   the value of an attribute
330 * @throws IOException
331 */
332
333    protected void write(String key, String value)
334    throws IOException {
335        os.write(SPACE);
336        write(key);
337        os.write(EQUALS);
338        os.write(QUOTE);
339        write(value);
340        os.write(QUOTE);
341    }
342
343/**
344 * Writes a starttag to the outputstream.
345 *
346 * @param   tag     the name of the tag
347 * @throws IOException
348 */
349
350    protected void writeStart(String tag)
351    throws IOException {
352        os.write(LT);
353        write(tag);
354    }
355
356/**
357 * Writes an endtag to the outputstream.
358 *
359 * @param   tag     the name of the tag
360 * @throws IOException
361 */
362
363    protected void writeEnd(String tag)
364    throws IOException {
365        os.write(LT);
366        os.write(FORWARD);
367        write(tag);
368        os.write(GT);
369    }
370
371/**
372 * Writes an endtag to the outputstream.
373 * @throws IOException
374 */
375
376    protected void writeEnd()
377    throws IOException {
378        os.write(SPACE);
379        os.write(FORWARD);
380        os.write(GT);
381    }
382
383/**
384 * Writes the markup attributes of the specified <CODE>MarkupAttributes</CODE>
385 * object to the <CODE>OutputStream</CODE>.
386 * @param markup   a <CODE>Properties</CODE> collection to write.
387 * @return true, if writing the markup attributes succeeded
388 * @throws IOException
389 */
390    protected boolean writeMarkupAttributes(Properties markup)
391    throws IOException {
392        if (markup == null) return false;
393        Iterator<Object> attributeIterator = markup.keySet().iterator();
394        String name;
395        while (attributeIterator.hasNext()) {
396                name = String.valueOf(attributeIterator.next());
397                write(name, markup.getProperty(name));
398        }
399        markup.clear();
400        return true;
401    }
402
403    /** Checks if the stream is to be closed on document close
404     * @return true if the stream is closed on document close
405     *
406     */
407    public boolean isCloseStream() {
408        return closeStream;
409    }
410
411    /** Sets the close state of the stream after document close
412     * @param closeStream true if the stream is closed on document close
413     *
414     */
415    public void setCloseStream(boolean closeStream) {
416        this.closeStream = closeStream;
417    }
418
419    /**
420     * @see com.itextpdf.text.DocListener#setMarginMirroring(boolean)
421     */
422    public boolean setMarginMirroring(boolean MarginMirroring) {
423        return false;
424    }
425
426    /**
427     * @see com.itextpdf.text.DocListener#setMarginMirroring(boolean)
428     * @since   2.1.6
429     */
430    public boolean setMarginMirroringTopBottom(boolean MarginMirroring) {
431        return false;
432    }
433
434}