⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rarfile.java

📁 RARoScope是一个用于扫描和列举这个RAR压缩文档内容的Java类库。它能够读取RAR文档大部分可用信息包括:1.完整的文件名包括路径。2.文件被修改/创建的日期和时间。3.压缩过的文件大小。4
💻 JAVA
字号:
/*
 * RARoScope - Java Library for Scanning RAR Archives
 * 
 * Copyright 2008 Adarsh Ramamurthy 
 * 
 * Licensed 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.
 * 
 * Homepage: http://www.adarshr.com/papers/raroscope
 */

package com.adarshr.raroscope;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.NoSuchElementException;

/**
 * Represents a RAR archive.
 * <p>
 * This class is used to enumerate the entries in a RAR file.
 * 
 * @author Adarsh Ramamurthy
 * 
 * @version 1.0, 10th March 2008
 */
public class RARFile
{
    /**
     * The underlying stream.
     */
    private InputStream stream;
    
    /**
     * Marker block of RAR archives. It is "Rar!" in reverse bytes.
     */
    private static final long MARKER = 0x21726152L;
    
    /**
     * To hold the available bytes in the stream.
     */
    private long available;
    
    /**
     * Constructs an instance of <tt>RARFile</tt> for performing operations
     * on the archive.
     * 
     * @param name the RAR file name.
     * 
     * @throws IOException in case of errors reading from the archive.
     */
    public RARFile(String name) throws IOException
    {
        this(new File(name));
    }
    
    /**
     * Constructs an instance of <tt>RARFile</tt> for performing operations
     * on the archive.
     * 
     * @param file the RAR file.
     * 
     * @throws IOException in case of errors reading from the archive.
     */
    public RARFile(File file) throws IOException
    {
        this.stream = new FileInputStream(file);
        
        this.available = this.stream.available();
        
        byte[] headers = new byte[7 + 13];
        
        // Read the Marker Block and Archive Header Blocks.
        this.stream.read(headers);
        
        if(MARKER != getLong(headers, 0, 3))
        {
            throw new IOException("Invalid RAR archive");
        }
    }
    
    /**
     * Enumerates all the entries in the RAR archive.
     * 
     * @return an instance of <tt>Enumeration</tt> for displaying the entries.
     * 
     * @see RAREntry
     */
    public Enumeration<RAREntry> entries()
    {
        return new Enumeration<RAREntry>() {
        
            public RAREntry nextElement()
            {
                byte[] buf = new byte[32];
                
                RAREntry entry = null;
                
                try
                {
                    RARFile.this.available -= RARFile.this.stream.read(buf);
                    
                    int type = buf[2] & 0xFF;
                    
                    // Means File Header Block
                    if(type == 0x74)
                    {
                        entry = new RAREntry();
                        
                        long flags = getLong(buf, 3, 4);
                        
                        entry.setDirectory((flags & 0xE0) == 0xE0);
                        
                        long pSize = getLong(buf, 7, 10);
                        long size = getLong(buf, 11, 14);
                        
                        // Very large file ( > 2GB )
                        if((flags & 0x100) == 0x100)
                        {
                            byte[] hiBytes = new byte[8];
                            
                            RARFile.this.available -= 
                                RARFile.this.stream.read(hiBytes);
                            
                            pSize = getLong(hiBytes, 0, 4) << 32 | pSize;
                            size = getLong(hiBytes, 5, 8) << 32 | size;
                        }
                        
                        long hSize = getLong(buf, 5, 6);
                        
                        entry.setCompressedSize(pSize);
                        entry.setSize(getLong(buf, 11, 14));
                        entry.setHostOS(toOS(buf[15] & 0xFF));
                        entry.setCrc(getLong(buf, 16, 19));
                        entry.setTime(toDate(getLong(buf, 20, 23)));
                        entry.setVersion(toVersion(buf[24] & 0xFF));
                        entry.setMethod(toMethod(buf[25] & 0xFF));
                        
                        long nSize = getLong(buf, 26, 27);
                        
                        byte[] name = new byte[(int)nSize];
                        
                        RARFile.this.available -= 
                            RARFile.this.stream.read(name);
                        
                        entry.setName(new String(name));
                        
                        RARFile.this.available -= 
                            RARFile.this.stream.skip(
                                hSize - (32 + nSize) + pSize);
                    }
                }
                catch (IOException e)
                {
                    throw new NoSuchElementException(e.getMessage());
                }
                
                if(entry == null)
                {
                    throw new NoSuchElementException();
                }
                
                return entry;
            }
            
            public boolean hasMoreElements()
            {
                return RARFile.this.available > 32;
            }
            
        };
    }
    
    /**
     * Closes the archive.
     * 
     * @throws IOException in case of errors while closing.
     */
    public void close() throws IOException
    {
        this.stream.close();
    }
    
    /**
     * Converts the input inverted array of bytes to a long representation.
     * 
     * @param bytes the byte array to be converted.
     * 
     * @return the long value.
     */
    protected long getLong(byte[] bytes)
    {
        long ret = 0;
        long mask = 0;
        
        for (int i = 0; i < bytes.length; i++)
        {
            ret |= (bytes[i] & 0xFF) << (8 * i); // mask and shift left
            mask = (mask << 8) | 0xFF; // generate the final mask
        }
        
        return ret & mask;
    }
    
    /**
     * Converts the input inverted array of bytes to a long representation.
     * Conversion is done inclusive of both the limits specified.
     * 
     * @param bytes the byte array to be converted.
     * 
     * @param start the index to start with.
     * 
     * @param end the end index.
     * 
     * @return the long value.
     */
    protected long getLong(byte[] bytes, int start, int end)
    {
        long ret = 0;
        long mask = 0;
        
        if(start < 0 || end >= bytes.length)
        {
            return ret;
        }
        
        for (int i = start, j = 0; i <= end; i++, j++)
        {
            ret |= (bytes[i] & 0xFF) << (8 * j); // mask and shift left
            mask = (mask << 8) | 0xFF; // generate the final mask
        }
        
        return ret & mask;
    }
    
    /**
     * Converts the DOS time to Java date.
     *  
     * @param dosTime MS DOS format time.
     * 
     * @return an instance of <tt>Date</tt>.
     */
    protected Date toDate(long dosTime)
    {
        Calendar calendar = Calendar.getInstance();
        
        calendar.set(
            (int)(((dosTime >> 25) & 0x7f) + 1980),  // year
            (int)(((dosTime >> 21) & 0x0f) - 1),  // month
            (int)((dosTime >> 16) & 0x1f),  // date
            (int)((dosTime >> 11) & 0x1f),  // hours
            (int)((dosTime >> 5) & 0x3f),  // minutes
            (int)((dosTime << 1) & 0x3e));  // seconds
        
        return calendar.getTime();
    }
    
    /**
     * Translate the OS byte to a human readable string.
     * 
     * @param o the number to be translated (1 byte).
     * 
     * @return the OS string.
     */
    protected String toOS(int o)
    {
        String os = null;
        
        switch(o)
        {
            case 0: 
                os = "MS DOS";
                break;
                
            case 1: 
                os = "OS/2";
                break;
                
            case 2: 
                os = "Win32";
                break;
                
            case 3: 
                os = "Unix";
                break;
                
            case 4: 
                os = "Mac OS";
                break;
                
            case 5:
                os = "BeOS";
                break;
                
            default:
                os = "Unknown";
                break;
        }
        
        return os;
    }
    
    /**
     * Decodes the version information. Version number will be of the format
     * 10 * Major Version + Minor Version.
     * 
     * @param v the version number.
     * 
     * @return the decoded version in the format "major.minor".
     */
    protected String toVersion(int v)
    {
        return String.valueOf(v/10F);
    }
    
    /**
     * Translates the compression method into a string.
     * 
     * @param m the compression method number.
     * 
     * @return the compression method string.
     */
    protected String toMethod(int m)
    {
        String method = null;
        
        switch (m)
        {
            case 0x30:
                method = "Storing";
                break;
                
            case 0x31:
                method = "Fastest Compression";
                break;
                
            case 0x32:
                method = "Fast Compression";
                break;
                
            case 0x33:
                method = "Normal Compression";
                break;
               
            case 0x34:
                method = "Good Compression";
                break;

            case 0x35:
                method = "Best Compression";
                break;
                
            default:
                method = "Unknown";
                break;
        }
        
        return method;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -