104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet/*
204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * Copyright (C) 2011 The Android Open Source Project
304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet *
404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * you may not use this file except in compliance with the License.
604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * You may obtain a copy of the License at
704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet *
804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet *
1004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
1104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
1204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * See the License for the specific language governing permissions and
1404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * limitations under the License.
1504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet */
1604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
1704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetpackage com.android.layoutlib.bridge.impl;
1804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
1904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
2004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport org.kxml2.io.KXmlParser;
2104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport org.xmlpull.v1.XmlPullParser;
2204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport org.xmlpull.v1.XmlPullParserException;
2304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
24c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohetimport java.io.BufferedInputStream;
25c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohetimport java.io.ByteArrayInputStream;
2604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.File;
2704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.FileInputStream;
2804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.FileNotFoundException;
29c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohetimport java.io.IOException;
3004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetimport java.io.InputStream;
3104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
3204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet/**
3304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet * A factory for {@link XmlPullParser}.
3404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet *
3504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet */
3604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohetpublic class ParserFactory {
3704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
3804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    private final static String ENCODING = "UTF-8"; //$NON-NLS-1$
3904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
4004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    public final static boolean LOG_PARSER = false;
4104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
4204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    public static XmlPullParser create(File f)
4304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet            throws XmlPullParserException, FileNotFoundException {
44c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        InputStream stream = new FileInputStream(f);
45c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        return create(stream, f.getName(), f.length());
4604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    }
4704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
4804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    public static XmlPullParser create(InputStream stream, String name)
49c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        throws XmlPullParserException {
50c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        return create(stream, name, -1);
51c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet    }
52c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
53c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet    private static XmlPullParser create(InputStream stream, String name, long size)
5404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet            throws XmlPullParserException {
5504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        KXmlParser parser = instantiateParser(name);
56c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
57c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        stream = readAndClose(stream, name, size);
58c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
5904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        parser.setInput(stream, ENCODING);
6004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        return parser;
6104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    }
6204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
6304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    private static KXmlParser instantiateParser(String name) throws XmlPullParserException {
6404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        KXmlParser parser;
6504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        if (name != null) {
6604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet            parser = new CustomParser(name);
6704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        } else {
6804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet            parser = new KXmlParser();
6904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        }
7004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
7104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        return parser;
7204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    }
7304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
74c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet    private static InputStream readAndClose(InputStream stream, String name, long size)
75c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            throws XmlPullParserException {
76c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        // just a sanity check. It's doubtful we'll have such big files!
77c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        if (size > Integer.MAX_VALUE) {
78c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            throw new XmlPullParserException("File " + name + " is too big to be parsed");
79c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        }
80c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        int intSize = (int) size;
81c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
82c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        // create a buffered reader to facilitate reading.
83c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        BufferedInputStream bufferedStream = new BufferedInputStream(stream);
84c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        try {
85c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            int avail;
86c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            if (intSize != -1) {
87c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                avail = intSize;
88c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            } else {
89c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                // get the size to read.
90c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                avail = bufferedStream.available();
91c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            }
92c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
93c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            // create the initial buffer and read it.
94c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            byte[] buffer = new byte[avail];
95c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            int read = stream.read(buffer);
96c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
97c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            // this is the easy case.
98c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            if (read == intSize) {
99c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                return new ByteArrayInputStream(buffer);
100c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            }
101c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
102c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            // check if there is more to read (read() does not necessarily read all that
103c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            // available() returned!)
104c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            while ((avail = bufferedStream.available()) > 0) {
105c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                if (read + avail > buffer.length) {
106c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                    // just allocate what is needed. We're mostly reading small files
107c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                    // so it shouldn't be too problematic.
108c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                    byte[] moreBuffer = new byte[read + avail];
109c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                    System.arraycopy(buffer, 0, moreBuffer, 0, read);
110c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                    buffer = moreBuffer;
111c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                }
112c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
113c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                read += stream.read(buffer, read, avail);
114c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            }
115c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
116c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            // return a new stream encapsulating this buffer.
117c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            return new ByteArrayInputStream(buffer);
118c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
119c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        } catch (IOException e) {
120c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            throw new XmlPullParserException("Failed to read " + name, null, e);
121c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        } finally {
122c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            try {
123c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet                bufferedStream.close();
124c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            } catch (IOException e) {
125c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet            }
126c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet        }
127c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet    }
128c48b0b940d632b9862ff6aa32665e37fe9e50845Xavier Ducrohet
12904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    private static class CustomParser extends KXmlParser {
13004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        private final String mName;
13104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
13204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        CustomParser(String name) {
13304ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet            super();
13404ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet            mName = name;
13504ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        }
13604ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet
13704ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        @Override
13804ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        public String toString() {
13904ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet            return mName;
14004ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet        }
14104ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet    }
14204ce81113107d2bfa0b8248b13145b4cf24cb943Xavier Ducrohet}
143