com.github.junrar.vfs2.provider.rar.RARFileSystem.java Source code

Java tutorial

Introduction

Here is the source code for com.github.junrar.vfs2.provider.rar.RARFileSystem.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.junrar.vfs2.provider.rar;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.vfs2.Capability;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystem;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.provider.AbstractFileName;
import org.apache.commons.vfs2.provider.AbstractFileSystem;
import org.apache.commons.vfs2.provider.UriParser;

import com.github.junrar.Archive;
import com.github.junrar.exception.RarException;
import com.github.junrar.rarfile.FileHeader;

/**
 * A read-only file system for RAR files.
 * 
 * @author <a href="http://www.rogiel.com">Rogiel</a>
 */
public class RARFileSystem extends AbstractFileSystem implements FileSystem {
    private final FileObject parentLayer;

    private Archive archive;
    private Map<String, FileHeader> files = new HashMap<String, FileHeader>();

    public RARFileSystem(final AbstractFileName rootName, final FileObject parentLayer,
            final FileSystemOptions fileSystemOptions) throws FileSystemException {
        super(rootName, parentLayer, fileSystemOptions);
        this.parentLayer = parentLayer;
    }

    @Override
    public void init() throws FileSystemException {
        super.init();

        try {
            try {
                archive = new Archive(new VFSVolumeManager(parentLayer));
                // Build the index
                List<RARFileObject> strongRef = new ArrayList<RARFileObject>(100);
                for (final FileHeader header : archive.getFileHeaders()) {
                    AbstractFileName name = (AbstractFileName) getFileSystemManager().resolveName(getRootName(),
                            UriParser.encode(header.getFileNameString()));

                    // Create the file
                    RARFileObject fileObj;
                    if (header.isDirectory() && getFileFromCache(name) != null) {
                        fileObj = (RARFileObject) getFileFromCache(name);
                        fileObj.setHeader(header);
                        continue;
                    }

                    fileObj = createRARFileObject(name, header);
                    putFileToCache(fileObj);
                    strongRef.add(fileObj);
                    fileObj.holdObject(strongRef);

                    // Make sure all ancestors exist
                    RARFileObject parent;
                    for (AbstractFileName parentName = (AbstractFileName) name
                            .getParent(); parentName != null; fileObj = parent, parentName = (AbstractFileName) parentName
                                    .getParent()) {
                        // Locate the parent
                        parent = (RARFileObject) getFileFromCache(parentName);
                        if (parent == null) {
                            parent = createRARFileObject(parentName, null);
                            putFileToCache(parent);
                            strongRef.add(parent);
                            parent.holdObject(strongRef);
                        }

                        // Attach child to parent
                        parent.attachChild(fileObj.getName());
                    }
                }

            } catch (RarException e) {
                throw new FileSystemException(e);
            } catch (IOException e) {
                throw new FileSystemException(e);
            }
        } finally {
            // closeCommunicationLink();
        }
    }

    protected RARFileObject createRARFileObject(final AbstractFileName name, final FileHeader header)
            throws FileSystemException {
        return new RARFileObject(name, archive, header, this);
    }

    @Override
    protected void doCloseCommunicationLink() {
        try {
            archive.close();
        } catch (FileSystemException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Returns the capabilities of this file system.
     */
    @Override
    protected void addCapabilities(final Collection<Capability> caps) {
        caps.addAll(RARFileProvider.capabilities);
    }

    /**
     * Creates a file object.
     */
    @Override
    protected FileObject createFile(final AbstractFileName name) throws FileSystemException {
        String path = name.getPath().substring(1);
        if (path.length() == 0) {
            return new RARFileObject(name, archive, null, this);
        } else if (files.containsKey(name.getPath())) {
            return new RARFileObject(name, archive, files.get(name.getPath()), this);
        }
        return null;
    }

    /**
     * will be called after all file-objects closed their streams.
     */
    protected void notifyAllStreamsClosed() {
        closeCommunicationLink();
    }
}