Package com.github.stephenc.javaisotools.eltorito.impl

Source Code of com.github.stephenc.javaisotools.eltorito.impl.ElToritoHandler

/*
* Copyright (c) 2010. Stephen Connolly.
* Copyright (C) 2007. Jens Hatlak <hatlak@rbg.informatik.tu-darmstadt.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

package com.github.stephenc.javaisotools.eltorito.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;

import com.github.stephenc.javaisotools.iso9660.ISO9660File;
import com.github.stephenc.javaisotools.iso9660.LayoutHelper;
import com.github.stephenc.javaisotools.iso9660.impl.ISO9660Constants;
import com.github.stephenc.javaisotools.iso9660.impl.ISO9660Element;
import com.github.stephenc.javaisotools.iso9660.sabre.impl.LSBFWordDataReference;
import com.github.stephenc.javaisotools.iso9660.volumedescriptors.BootRecord;
import com.github.stephenc.javaisotools.sabre.Element;
import com.github.stephenc.javaisotools.sabre.HandlerException;
import com.github.stephenc.javaisotools.sabre.impl.ChainingStreamHandler;
import com.github.stephenc.javaisotools.sabre.impl.FileDataReference;
import com.github.stephenc.javaisotools.iso9660.impl.LogicalSectorElement;
import com.github.stephenc.javaisotools.sabre.Fixup;
import com.github.stephenc.javaisotools.sabre.StreamHandler;

public class ElToritoHandler extends ChainingStreamHandler {

    private ElToritoConfig config;
    private Fixup bootCatalogLocation, bootImageLocation;

    public ElToritoHandler(StreamHandler streamHandler, ElToritoConfig config) {
        super(streamHandler, streamHandler);
        this.config = config;
    }

    public void startElement(Element element) throws HandlerException {
        if (element instanceof ISO9660Element) {
            String id = (String) element.getId();
            process(id);
        }
        super.startElement(element);
    }

    private void process(String id) throws HandlerException {
        if (id.equals("VDS")) {
            doBVD();
        } else if (id.equals("BIA")) {
            doCatalog();
        }
        if (id.equals("BDA")) {
            doImage();
        }
    }

    private void doBVD() throws HandlerException {
        super.startElement(new LogicalSectorElement("BR"));

        LayoutHelper helper = new ElToritoLayoutHelper(this);
        BootRecord br = new BootRecord(this, helper);
        br.setMetadata(config);
        br.doBR();

        // Remember Boot System Use (absolute pointer to first sector of Boot Catalog)
        bootCatalogLocation = fixup(new LSBFWordDataReference(0));

        super.endElement();
    }

    private void doCatalog() throws HandlerException {
        super.startElement(new LogicalSectorElement("BCAT"));

        // Write and close Boot Catalog Location Fixup
        long position = mark();
        int location = (int) (position / ISO9660Constants.LOGICAL_BLOCK_SIZE);
        bootCatalogLocation.data(new LSBFWordDataReference(location));
        bootCatalogLocation.close();

        ElToritoFactory etf = new ElToritoFactory(this);

        // Validation Entry
        int platformID = config.getPlatformID();
        String idString = config.getIDString();
        etf.doValidationEntry(platformID, idString);

        // Initial/Default Entry
        boolean bootable = config.getBootable();
        int bootMediaType = config.getBootMediaType();
        int loadSegment = config.getLoadSegment();
        int systemType = config.getSystemType();
        int sectorCount = config.getSectorCount();
        bootImageLocation = etf.doDefaultEntry(bootable, bootMediaType, loadSegment, systemType, sectorCount);

        super.endElement();
    }

    private void doImage() throws HandlerException {
        super.startElement(new LogicalSectorElement("BIMG"));

        // Write and close Boot Image Location Fixup
        long position = mark();
        int location = (int) (position / ISO9660Constants.LOGICAL_BLOCK_SIZE);
        bootImageLocation.data(new LSBFWordDataReference(location));
        bootImageLocation.close();

        if (config.getGenBootInfoTable()) {
            this.genBootInfoTable(location);
        }

        // Write Boot Image
        data(config.getBootImage().getDataReference());

        super.endElement();
    }

    private void genBootInfoTable(int lba) throws HandlerException {
        // Patch the Boot Image: write 56 byte boot information table
        // (cf. man mkisofs, section EL TORITO BOOT INFORMATION TABLE)
        try {
            String orgName = config.getBootImage().getAbsolutePath();
            File orgFile = new File(orgName);

            // Compute the checksum over all 32-bit words starting at byte offset 64
            FileInputStream fis = new FileInputStream(orgFile);
            fis.skip(64);
            long checksum = 0;
            byte[] buffer = new byte[0x2000];
            while (fis.available() > 0) {
                int len = fis.read(buffer);
                for (int i = 0; i < len;) {
                    long temp = buffer[i++] & 0xFF;
                    temp |= (buffer[i++] << 8) & 0xFF00;
                    temp |= (buffer[i++] << 16) & 0xFF0000;
                    temp |= (buffer[i++] << 24) & 0xFF000000l;
                    checksum += temp;
                }
            }
            fis.close();

            // Create the patched file
            fis = new FileInputStream(orgFile);
            File patchedFile = new File(orgName + ".mod");
            FileOutputStream fos = new FileOutputStream(patchedFile);

            // Copy first 8 bytes
            buffer = new byte[8];
            fis.read(buffer);
            fos.write(buffer);

            // Read 56 bytes and init the buffer with as many 0 bytes
            buffer = new byte[56];
            fis.read(buffer);
            Arrays.fill(buffer, (byte) 0);

            // Write boot info tables fields
            int i = 0;
            // PVD LBA (always 16), 7.3.1 format
            int pvd = 16;
            buffer[i++] = (byte) (pvd & 0xFF);
            buffer[i++] = (byte) ((pvd >> 8) & 0xFF);
            buffer[i++] = (byte) ((pvd >> 16) & 0xFF);
            buffer[i++] = (byte) ((pvd >> 24) & 0xFF);
            // Boot file LBA, 7.3.1 format
            buffer[i++] = (byte) (lba & 0xFF);
            buffer[i++] = (byte) ((lba >> 8) & 0xFF);
            buffer[i++] = (byte) ((lba >> 16) & 0xFF);
            buffer[i++] = (byte) ((lba >> 24) & 0xFF);
            // Boot file length in bytes, 7.3.1 format
            int len = (int) config.getBootImage().length();
            buffer[i++] = (byte) (len & 0xFF);
            buffer[i++] = (byte) ((len >> 8) & 0xFF);
            buffer[i++] = (byte) ((len >> 16) & 0xFF);
            buffer[i++] = (byte) ((len >> 24) & 0xFF);
            // 32-bit checksum, 7.3.1 format
            buffer[i++] = (byte) (checksum & 0xFF);
            buffer[i++] = (byte) ((checksum >> 8) & 0xFF);
            buffer[i++] = (byte) ((checksum >> 16) & 0xFF);
            buffer[i++] = (byte) ((checksum >> 24) & 0xFF);
            // Write 38 byte buffer
            fos.write(buffer);

            // Write the rest
            buffer = new byte[0x2000];
            while (fis.available() > 0) {
                len = fis.read(buffer);
                fos.write(buffer, 0, len);
            }
            fis.close();
            fos.close();

            // Replace original file by patched one
            orgFile.delete();
            orgFile = new File(orgName);
            patchedFile.renameTo(orgFile);
            config.setBootImage(new ISO9660File(orgFile));

            System.out.println("Patched boot image at " + orgFile.getPath());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
TOP

Related Classes of com.github.stephenc.javaisotools.eltorito.impl.ElToritoHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.