All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.verapdf.pd.font.cff.CFFFileBaseParser Maven / Gradle / Ivy

/**
 * This file is part of veraPDF Parser, a module of the veraPDF project.
 * Copyright (c) 2015, veraPDF Consortium 
 * All rights reserved.
 *
 * veraPDF Parser is free software: you can redistribute it and/or modify
 * it under the terms of either:
 *
 * The GNU General public license GPLv3+.
 * You should have received a copy of the GNU General Public License
 * along with veraPDF Parser as the LICENSE.GPL file in the root of the source
 * tree.  If not, see http://www.gnu.org/licenses/ or
 * https://www.gnu.org/licenses/gpl-3.0.en.html.
 *
 * The Mozilla Public License MPLv2+.
 * You should have received a copy of the Mozilla Public License along with
 * veraPDF Parser as the LICENSE.MPL file in the root of the source tree.
 * If a copy of the MPL was not distributed with this file, you can obtain one at
 * http://mozilla.org/MPL/2.0/.
 */
package org.verapdf.pd.font.cff;

import org.verapdf.as.io.ASInputStream;
import org.verapdf.io.SeekableInputStream;
import org.verapdf.pd.font.CFFNumber;

import java.io.IOException;

/**
 * This class does low-level parsing of CFF file.
 *
 * @author Sergey Shemyakov
 */
class CFFFileBaseParser {

    protected SeekableInputStream source;
    protected CFFIndex definedNames;

    CFFFileBaseParser(ASInputStream source) throws IOException {
        this.source = SeekableInputStream.getSeekableStream(source);
    }

    CFFFileBaseParser(SeekableInputStream source) {
        this.source = source;
    }

    protected int readCard8() throws IOException {
        return this.source.readByte() & 0xFF;
    }

    protected int readCard16() throws IOException {
        int highOrder = (this.source.readByte() & 0xFF) << 8;
        return highOrder | (this.source.readByte() & 0xFF);
    }

    private long readOffset(int offSize) throws IOException {
        long res = 0;
        for (int i = 0; i < offSize - 1; ++i) {
            res |= (this.source.readByte() & 0xFF);
            res <<= 8;
        }
        res |= (this.source.readByte() & 0xFF);
        return res;
    }

    protected CFFIndex readIndex() throws IOException {
        int count = readCard16();
        if (count == 0) {
            return new CFFIndex(0, 0, new int[0], new byte[0]);
        }
        int offSize = readCard8();
        int[] offset = new int[count + 1];
        for (int i = 0; i < count + 1; ++i) {
            offset[i] = (int) readOffset(offSize);
        }
        byte[] data = new byte[offset[count] - 1];
        if (source.read(data, data.length) != data.length) {
            throw new IOException("End of stream is reached");
        }
        int offsetShift = 3 + offSize * (count + 1);
        return new CFFIndex(count, offsetShift, offset, data);
    }

    protected void readHeader() throws IOException {
        readCard8();
        readCard8();
        int hdrSize = readCard8();
        this.source.seek(hdrSize);
    }

    private float readReal() throws IOException {
        StringBuilder builder = new StringBuilder();
        int buf;
        parsing:
        while (true) {
            buf = readCard8();
            int[] hexs = new int[2];
            hexs[0] = buf >> 4;
            hexs[1] = buf & 0x0F;
            for (int i = 0; i < 2; ++i) {
                if (hexs[i] < 10) {
                    builder.append(hexs[i]);
                } else {
                    switch (hexs[i]) {
                        case 0x0A:
                            builder.append('.');
                            break;
                        case 0x0B:
                            builder.append('E');
                            break;
                        case 0x0C:
                            builder.append("E-");
                            break;
                        case 0x0E:
                            builder.append('-');
                            break;
                        case 0x0F:
                            break parsing;
                        default:    // Can not be reached
                            break parsing;
                    }
                }
            }
        }
        return Float.parseFloat(builder.toString());
    }

    private int readInteger(byte b) throws IOException {
        int firstByteValue = b & 0xFF;
        if (firstByteValue > 31 && firstByteValue < 247) {
            return firstByteValue - 139;
        }
        if (firstByteValue > 246 && firstByteValue < 251) {
            int first = (firstByteValue - 247) << 8;
            return first + readCard8() + 108;
        }
        if (firstByteValue > 250 && firstByteValue < 255) {
            int first = (firstByteValue - 251) << 8;
            return -first - readCard8() - 108;
        }
        if (firstByteValue == 28) {
            return readCard16();
        }
        if (firstByteValue == 29) {
            return (readCard16() << 16) | readCard16();
        } else {    // Shouldn't be reached
            throw new IOException("Can't read integer");
        }
    }

    protected CFFNumber readNumber() throws IOException {
        byte first = this.source.readByte();
        if (first == 0x1E) {
            return new CFFNumber(this.readReal());
        } else {
            return new CFFNumber(this.readInteger(first));
        }
    }

    protected String getStringBySID(int sid) throws IOException {
        try {
            if (sid < CFFPredefined.N_STD_STRINGS) {
                return CFFPredefined.STANDARD_STRINGS[sid];
            } else {
                return new String(this.definedNames.get(sid -
                        CFFPredefined.N_STD_STRINGS));
            }
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new IOException("Can't get string with given SID", e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy