1 /***
2 *
3 */
4 package com.fernsroth.squashfs;
5
6 import java.io.File;
7 import java.io.IOException;
8 import java.text.ParseException;
9 import java.util.Date;
10 import java.util.Stack;
11
12 import org.xml.sax.Attributes;
13 import org.xml.sax.InputSource;
14 import org.xml.sax.SAXException;
15 import org.xml.sax.helpers.DefaultHandler;
16
17 import com.fernsroth.squashfs.exception.SquashFSException;
18 import com.fernsroth.squashfs.model.BaseFile;
19 import com.fernsroth.squashfs.model.Directory;
20 import com.fernsroth.squashfs.model.Manifest;
21 import com.fernsroth.squashfs.model.SFSFile;
22 import com.fernsroth.squashfs.model.SFSSourceFile;
23 import com.fernsroth.squashfs.model.SymLink;
24
25 /***
26 *
27 * @author Joseph M. Ferner (Near Infinity Corporation)
28 */
29 public class ManifestSAXHandler extends DefaultHandler {
30
31 /***
32 * the manifest.
33 */
34 private Manifest manifest;
35
36 /***
37 * object stack to keep track of location during sax calls.
38 */
39 private Stack<Object> objectStack = new Stack<Object>();
40
41 /***
42 * the source directory.
43 */
44 private File sourceDir;
45
46 /***
47 * the system.
48 */
49 private static SquashFSSystem system = new DefaultSquashFSSystem();
50
51 /***
52 * constructor.
53 * @param sourceDir the source directory.
54 */
55 public ManifestSAXHandler(File sourceDir) {
56 this.sourceDir = sourceDir;
57 }
58
59 /***
60 * {@inheritDoc}
61 */
62 @Override
63 public InputSource resolveEntity(String publicId, String systemId)
64 throws IOException, SAXException {
65 if (publicId.equals(SquashFSGlobals.DOCTYPE_PUBLIC)) {
66 return new InputSource(getClass().getResourceAsStream(
67 "/jSquashfs-1.0.dtd"));
68 }
69 return super.resolveEntity(publicId, systemId);
70 }
71
72 /***
73 * gets the root directory.
74 * @return the root directory.
75 */
76 public Manifest getManifest() {
77 return this.manifest;
78 }
79
80 /***
81 * {@inheritDoc}
82 */
83 @Override
84 public void endElement(String uri, String localName, String qName)
85 throws SAXException {
86 this.objectStack.pop();
87 super.endElement(uri, localName, qName);
88 }
89
90 /***
91 * {@inheritDoc}
92 */
93 @Override
94 public void startElement(String uri, String localName, String qName,
95 Attributes attributes) throws SAXException {
96 super.startElement(uri, localName, qName, attributes);
97
98 if (qName.equals("squashfs-manifest")) {
99 this.manifest = new Manifest();
100 this.objectStack.push(this.manifest);
101 }
102
103 else if (qName.equals("root-directory") || qName.equals("directory")
104 || qName.equals("file") || qName.equals("symbolic-link")) {
105 long uid = Long.parseLong(attributes.getValue("uid"));
106 long guid = Long.parseLong(attributes.getValue("guid"));
107 Date dateMTime;
108 String strMTime = attributes.getValue("mtime");
109 try {
110 if (strMTime == null) {
111 dateMTime = system.getCurrentDate();
112 } else {
113 dateMTime = SquashFSUtils.ISO8601_FORMAT.parse(strMTime);
114 }
115 } catch (ParseException e) {
116 throw new SAXException("could not parse mtime '" + strMTime
117 + "'", e);
118 }
119 long mTime = SquashFSUtils.getMTimeFromDate(dateMTime);
120 int mode = SquashFSUtils.getModeFromString(attributes
121 .getValue("mode"));
122 String name = attributes.getValue("name");
123
124 if (qName.equals("root-directory") || qName.equals("directory")) {
125 Directory dir = new Directory(name, mode, mTime, guid, uid);
126 try {
127 addToParent(this.objectStack.peek(), dir);
128 } catch (SquashFSException e) {
129 throw new SAXException("adding item to parent", e);
130 }
131 this.objectStack.push(dir);
132 }
133
134 else if (qName.equals("file")) {
135 String fileName = attributes.getValue("file");
136 File sourceFile = null;
137 if (fileName != null) {
138 sourceFile = new File(this.sourceDir, fileName);
139 }
140 SFSFile file = new SFSSourceFile(name, mode, mTime, guid, uid,
141 sourceFile);
142 try {
143 addToParent(this.objectStack.peek(), file);
144 } catch (SquashFSException e) {
145 throw new SAXException("adding item to parent", e);
146 }
147 this.objectStack.push(file);
148 }
149
150 else if (qName.equals("symbolic-link")) {
151 String linkName = attributes.getValue("link");
152 SymLink link = new SymLink(name, mode, mTime, guid, uid,
153 linkName);
154 try {
155 addToParent(this.objectStack.peek(), link);
156 } catch (SquashFSException e) {
157 throw new SAXException("adding item to parent", e);
158 }
159 this.objectStack.push(link);
160 }
161 }
162
163 else {
164 throw new SAXException("unknown element '" + qName + "'");
165 }
166 }
167
168 /***
169 * adds an object to it's parent.
170 * @param parent the parent to add it to.
171 * @param obj the object to add.
172 * @throws SquashFSException
173 */
174 private void addToParent(Object parent, Object obj)
175 throws SquashFSException {
176 if (parent instanceof Manifest) {
177 ((Manifest) parent).setRoot((Directory) obj);
178 } else if (parent instanceof Directory) {
179 ((Directory) parent).addSubentry((BaseFile) obj);
180 } else {
181 throw new SquashFSException("invalid parent '"
182 + parent.getClass().getName() + "' for child '"
183 + obj.getClass().getName() + "'");
184 }
185 }
186 }