1// This file is part of TagSoup and is Copyright 2002-2008 by John Cowan.
2//
3// TagSoup is licensed under the Apache License,
4// Version 2.0.  You may obtain a copy of this license at
5// http://www.apache.org/licenses/LICENSE-2.0 .  You may also have
6// additional legal rights not granted by this license.
7//
8// TagSoup is distributed in the hope that it will be useful, but
9// unless required by applicable law or agreed to in writing, TagSoup
10// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
11// OF ANY KIND, either express or implied; not even the implied warranty
12// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13//
14//
15// PYX Writer
16// FIXME: does not do escapes in attribute values
17// FIXME: outputs entities as bare '&' character
18
19package org.ccil.cowan.tagsoup;
20import java.io.*;
21import org.xml.sax.*;
22import org.xml.sax.ext.LexicalHandler;
23
24/**
25A ContentHandler that generates PYX format instead of XML.
26Primarily useful for debugging.
27**/
28public class PYXWriter
29	implements ScanHandler, ContentHandler, LexicalHandler {
30
31	private PrintWriter theWriter;		// where we write to
32	private static char[] dummy = new char[1];
33	private String attrName;		// saved attribute name
34
35	// ScanHandler implementation
36
37	public void adup(char[] buff, int offset, int length) throws SAXException {
38		theWriter.println(attrName);
39		attrName = null;
40		}
41
42	public void aname(char[] buff, int offset, int length) throws SAXException {
43		theWriter.print('A');
44		theWriter.write(buff, offset, length);
45		theWriter.print(' ');
46		attrName = new String(buff, offset, length);
47		}
48
49	public void aval(char[] buff, int offset, int length) throws SAXException {
50		theWriter.write(buff, offset, length);
51		theWriter.println();
52		attrName = null;
53		}
54
55	public void cmnt(char [] buff, int offset, int length) throws SAXException {
56//		theWriter.print('!');
57//		theWriter.write(buff, offset, length);
58//		theWriter.println();
59		}
60
61	public void entity(char[] buff, int offset, int length) throws SAXException { }
62
63	public int getEntity() { return 0; }
64
65	public void eof(char[] buff, int offset, int length) throws SAXException {
66		theWriter.close();
67		}
68
69	public void etag(char[] buff, int offset, int length) throws SAXException {
70		theWriter.print(')');
71		theWriter.write(buff, offset, length);
72		theWriter.println();
73		}
74
75	public void decl(char[] buff, int offset, int length) throws SAXException {
76        }
77
78	public void gi(char[] buff, int offset, int length) throws SAXException {
79		theWriter.print('(');
80		theWriter.write(buff, offset, length);
81		theWriter.println();
82		}
83
84	public void cdsect(char[] buff, int offset, int length) throws SAXException {
85		pcdata(buff, offset, length);
86		}
87
88	public void pcdata(char[] buff, int offset, int length) throws SAXException {
89		if (length == 0) return;	// nothing to do
90		boolean inProgress = false;
91		length += offset;
92		for (int i = offset; i < length; i++) {
93			if (buff[i] == '\n') {
94				if (inProgress) {
95					theWriter.println();
96					}
97				theWriter.println("-\\n");
98				inProgress = false;
99				}
100			else {
101				if (!inProgress) {
102					theWriter.print('-');
103					}
104				switch(buff[i]) {
105				case '\t':
106					theWriter.print("\\t");
107					break;
108				case '\\':
109					theWriter.print("\\\\");
110					break;
111				default:
112					theWriter.print(buff[i]);
113					}
114				inProgress = true;
115				}
116			}
117		if (inProgress) {
118			theWriter.println();
119			}
120		}
121
122	public void pitarget(char[] buff, int offset, int length) throws SAXException {
123		theWriter.print('?');
124		theWriter.write(buff, offset, length);
125		theWriter.write(' ');
126		}
127
128	public void pi(char[] buff, int offset, int length) throws SAXException {
129		theWriter.write(buff, offset, length);
130		theWriter.println();
131		}
132
133	public void stagc(char[] buff, int offset, int length) throws SAXException {
134//		theWriter.println("!");			// FIXME
135		}
136
137	public void stage(char[] buff, int offset, int length) throws SAXException {
138		theWriter.println("!");			// FIXME
139		}
140
141	// SAX ContentHandler implementation
142
143	public void characters(char[] buff, int offset, int length) throws SAXException {
144		pcdata(buff, offset, length);
145		}
146
147	public void endDocument() throws SAXException {
148		theWriter.close();
149		}
150
151	public void endElement(String uri, String localname, String qname) throws SAXException {
152		if (qname.length() == 0) qname = localname;
153		theWriter.print(')');
154		theWriter.println(qname);
155		}
156
157	public void endPrefixMapping(String prefix) throws SAXException { }
158
159	public void ignorableWhitespace(char[] buff, int offset, int length) throws SAXException {
160		characters(buff, offset, length);
161		}
162
163	public void processingInstruction(String target, String data) throws SAXException {
164		theWriter.print('?');
165		theWriter.print(target);
166		theWriter.print(' ');
167		theWriter.println(data);
168		}
169
170	public void setDocumentLocator(Locator locator) { }
171
172	public void skippedEntity(String name) throws SAXException { }
173
174	public void startDocument() throws SAXException { }
175
176	public void startElement(String uri, String localname, String qname,
177			Attributes atts) throws SAXException {
178		if (qname.length() == 0) qname=localname;
179		theWriter.print('(');
180		theWriter.println(qname);
181		int length = atts.getLength();
182		for (int i = 0; i < length; i++) {
183			qname = atts.getQName(i);
184			if (qname.length() == 0) qname = atts.getLocalName(i);
185			theWriter.print('A');
186//			theWriter.print(atts.getType(i));	// DEBUG
187			theWriter.print(qname);
188			theWriter.print(' ');
189			theWriter.println(atts.getValue(i));
190			}
191		}
192
193	public void startPrefixMapping(String prefix, String uri) throws SAXException { }
194
195	// Default LexicalHandler implementation
196
197	public void comment(char[] ch, int start, int length) throws SAXException {
198		cmnt(ch, start, length);
199		}
200	public void endCDATA() throws SAXException { }
201	public void endDTD() throws SAXException { }
202	public void endEntity(String name) throws SAXException { }
203	public void startCDATA() throws SAXException { }
204	public void startDTD(String name, String publicId, String systemId) throws SAXException { }
205	public void startEntity(String name) throws SAXException { }
206
207	// Constructor
208
209	public PYXWriter(Writer w) {
210		if (w instanceof PrintWriter) {
211			theWriter = (PrintWriter)w;
212			}
213		else {
214			theWriter = new PrintWriter(w);
215			}
216		}
217	}
218