Home | History | Annotate | Download | only in iso
      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