View Javadoc
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 }