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 }