1 /* 2 * Copyright 2012 Sebastian Annies, Hamburg 3 * 4 * Licensed under the Apache License, Version 2.0 (the License); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an AS IS BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.coremedia.iso; 17 18 import com.googlecode.mp4parser.AbstractBox; 19 import com.coremedia.iso.boxes.Box; 20 21 import java.io.BufferedInputStream; 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.lang.reflect.Constructor; 25 import java.lang.reflect.InvocationTargetException; 26 import java.net.URL; 27 import java.util.Enumeration; 28 import java.util.Properties; 29 import java.util.regex.Matcher; 30 import java.util.regex.Pattern; 31 32 /** 33 * A Property file based BoxFactory 34 */ 35 public class PropertyBoxParserImpl extends AbstractBoxParser { 36 Properties mapping; 37 38 public PropertyBoxParserImpl(String... customProperties) { 39 InputStream is = new BufferedInputStream(getClass().getResourceAsStream("/isoparser-default.properties")); 40 try { 41 mapping = new Properties(); 42 try { 43 mapping.load(is); 44 Enumeration<URL> enumeration = Thread.currentThread().getContextClassLoader().getResources("isoparser-custom.properties"); 45 46 while (enumeration.hasMoreElements()) { 47 URL url = enumeration.nextElement(); 48 InputStream customIS = new BufferedInputStream(url.openStream()); 49 try { 50 mapping.load(customIS); 51 } finally { 52 customIS.close(); 53 } 54 } 55 for (String customProperty : customProperties) { 56 mapping.load(new BufferedInputStream(getClass().getResourceAsStream(customProperty))); 57 } 58 } catch (IOException e) { 59 throw new RuntimeException(e); 60 } 61 } finally { 62 try { 63 is.close(); 64 } catch (IOException e) { 65 e.printStackTrace(); 66 // ignore - I can't help 67 } 68 } 69 } 70 71 public PropertyBoxParserImpl(Properties mapping) { 72 this.mapping = mapping; 73 } 74 75 Pattern p = Pattern.compile("(.*)\\((.*?)\\)"); 76 77 @SuppressWarnings("unchecked") 78 public Class<? extends Box> getClassForFourCc(String type, byte[] userType, String parent) { 79 FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke(); 80 try { 81 return (Class<? extends Box>) Class.forName(fourCcToBox.clazzName); 82 } catch (ClassNotFoundException e) { 83 throw new RuntimeException(e); 84 } 85 } 86 87 @Override 88 public Box createBox(String type, byte[] userType, String parent) { 89 90 FourCcToBox fourCcToBox = new FourCcToBox(type, userType, parent).invoke(); 91 String[] param = fourCcToBox.getParam(); 92 String clazzName = fourCcToBox.getClazzName(); 93 try { 94 if (param[0].trim().length() == 0) { 95 param = new String[]{}; 96 } 97 Class clazz = Class.forName(clazzName); 98 99 Class[] constructorArgsClazz = new Class[param.length]; 100 Object[] constructorArgs = new Object[param.length]; 101 for (int i = 0; i < param.length; i++) { 102 103 if ("userType".equals(param[i])) { 104 constructorArgs[i] = userType; 105 constructorArgsClazz[i] = byte[].class; 106 } else if ("type".equals(param[i])) { 107 constructorArgs[i] = type; 108 constructorArgsClazz[i] = String.class; 109 } else if ("parent".equals(param[i])) { 110 constructorArgs[i] = parent; 111 constructorArgsClazz[i] = String.class; 112 } else { 113 throw new InternalError("No such param: " + param[i]); 114 } 115 116 117 } 118 Constructor<AbstractBox> constructorObject; 119 try { 120 if (param.length > 0) { 121 constructorObject = clazz.getConstructor(constructorArgsClazz); 122 } else { 123 constructorObject = clazz.getConstructor(); 124 } 125 126 return constructorObject.newInstance(constructorArgs); 127 } catch (NoSuchMethodException e) { 128 throw new RuntimeException(e); 129 } catch (InvocationTargetException e) { 130 throw new RuntimeException(e); 131 } catch (InstantiationException e) { 132 throw new RuntimeException(e); 133 } catch (IllegalAccessException e) { 134 throw new RuntimeException(e); 135 } 136 137 138 } catch (ClassNotFoundException e) { 139 throw new RuntimeException(e); 140 } 141 } 142 143 private class FourCcToBox { 144 private String type; 145 private byte[] userType; 146 private String parent; 147 private String clazzName; 148 private String[] param; 149 150 public FourCcToBox(String type, byte[] userType, String parent) { 151 this.type = type; 152 this.parent = parent; 153 this.userType = userType; 154 } 155 156 public String getClazzName() { 157 return clazzName; 158 } 159 160 public String[] getParam() { 161 return param; 162 } 163 164 public FourCcToBox invoke() { 165 String constructor; 166 if (userType != null) { 167 if (!"uuid".equals((type))) { 168 throw new RuntimeException("we have a userType but no uuid box type. Something's wrong"); 169 } 170 constructor = mapping.getProperty((parent) + "-uuid[" + Hex.encodeHex(userType).toUpperCase() + "]"); 171 if (constructor == null) { 172 constructor = mapping.getProperty("uuid[" + Hex.encodeHex(userType).toUpperCase() + "]"); 173 } 174 if (constructor == null) { 175 constructor = mapping.getProperty("uuid"); 176 } 177 } else { 178 constructor = mapping.getProperty((parent) + "-" + (type)); 179 if (constructor == null) { 180 constructor = mapping.getProperty((type)); 181 } 182 } 183 if (constructor == null) { 184 constructor = mapping.getProperty("default"); 185 } 186 if (constructor == null) { 187 throw new RuntimeException("No box object found for " + type); 188 } 189 Matcher m = p.matcher(constructor); 190 boolean matches = m.matches(); 191 if (!matches) { 192 throw new RuntimeException("Cannot work with that constructor: " + constructor); 193 } 194 clazzName = m.group(1); 195 param = m.group(2).split(","); 196 return this; 197 } 198 } 199 } 200