BinarySource.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Компилятор языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    Copyright © 2021, 2024 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package ru.malik.elaborarer.avtoo.lang;

import avt.io.*;
import avt.io.extension.*;
import avt.lang.array.*;
import platform.independent.filesystem.*;
import platform.independent.streamformat.*;
import ru.malik.elaborarer.compression.zlib.*;

public class BinarySource(Object, InputAdapter, Source, Cloneable, Measureable, MutableObjectArray, ObjectArray, AVTOORecompilable, AVTOOConstants)
{
    private byte[] fldInputStream;
    private Object[] fldObjects;
    private ChunkArray fldChunks;
    private final ClassTypeArray fldDeclaredArray;
    private final String fldRelativePath;
    private final Library fldParentLibrary;
    private final Programme fldParentProgramme;

    public (Library parentLibrary, String relativePath) {
        fldObjects = new Object[0];
        fldDeclaredArray = new ClassTypeArray();
        fldRelativePath = relativePath != null ? relativePath : "";
        fldParentLibrary = parentLibrary;
        fldParentProgramme = parentLibrary == null ? null : parentLibrary.parentProgramme;
    }

    public void loadFromDataStream(DataInputStream stream) throws IOException { loadFromInputStream(stream == null ? null : stream.reader); }

    public void loadFromInputStream(ByteReader stream) throws IOException {
        if(stream == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "stream" }));
        }
        LimitedSizeExtension sizeable = (LimitedSizeExtension) stream.getExtension(LimitedSizeExtension.class);
        if(sizeable == null)
        {
            throw new InvalidStreamException(String.format(
                platform.independent.streamformat.package.getResourceString("invalid-stream.input.unsupported-extension"), new Object[] { LimitedSizeExtension.class.simpleName }
            ));
        }
        long size = sizeable.available();
        if(size < 0 || size > Int.MAX_VALUE)
        {
            throw new InvalidStreamException(platform.independent.streamformat.package.getResourceString("invalid-stream.input.size-too-large"));
        }
        int length = (int) size;
        byte[] data = new byte[length];
        int readed = stream.read(data, 0, length);
        data.length = readed >= 0 && readed <= length ? readed : 0;
        fldInputStream = data;
    }

    public void loadFromFileStream() throws IOException {
        Library parentLibrary = fldParentLibrary;
        FileSystem fileSystem;
        String sourcePath;
        if(parentLibrary == null)
        {
            fileSystem = Platform.instance.localFileSystem;
            sourcePath = "/" + fldRelativePath;
        } else
        {
            fileSystem = parentLibrary.fileSystem;
            sourcePath = parentLibrary.directoryPath + fldRelativePath;
        }
        ByteReader stream = fileSystem.openFileForRead(sourcePath);
        try
        {
            loadFromInputStream(stream);
        } finally
        {
            stream.close();
        }
    }

    public void parseInputStream() throws BinarySourceException {
        /* преобразование массива байт в поток ввода данных */
        byte[] source = fldInputStream;
        if(source == null)
        {
            throw new IllegalSourceStateException(package.getResourceString("binary-source.not-loaded"));
        }
        fldInputStream = null;
        int clength = 0;
        Chunk[] chunks = new Chunk[0x0f];
        ByteArrayInputStream stream = new ByteArrayInputStream(source);
        with((new DataInputStream(stream)).bigEndianDataInput, (Checksum32) new CRC32()) try
        {
            /* чтение сигнатуры */
            if(readLong() != SIGNATURE_AVTR)
            {
                throw new BinarySourceException(package.getResourceString("binary-source.format.invalid-signature")) { source = this, offset = (int) stream.position() };
            }
            /* чтение кусков */
            while(stream.available() > 0)
            {
                int dlength = readInt();
                if(dlength > (Int.MAX_VALUE - 4 >> 1) || dlength < 0)
                {
                    throw new BinarySourceException(package.getResourceString("binary-source.format.invalid-chunk-length")) { source = this, offset = (int) stream.position() };
                }
                if(dlength > ((int) stream.available() - 4 >> 1))
                {
                    throw new BinarySourceException(package.getResourceString("binary-source.format.invalid-markup")) { source = this, offset = (int) stream.position() };
                }
                int offset = (int) stream.position();
                int type = readInt();
                byte[] data = new byte[dlength << 1];
                readFully(data);
                int hash = readInt();
                update(source, offset, dlength + 2 << 1);
                if(value != hash)
                {
                    throw new BinarySourceException(package.getResourceString("binary-source.format.invalid-checksum")) { source = this, offset = (int) stream.position() };
                }
                reset();
                if(clength == chunks.length) Array.copy(chunks, 0, chunks = new Chunk[clength << 1 | 1], 0, clength);
                chunks[clength++] = new Chunk(offset, type, data, hash);
                if(type == CHUNK_IEND) break;
            }
        } catch(IOException exception)
        {
            throw new BinarySourceException(exception.message, exception) { source = this, offset = (int) stream.position() };
        }
        /* обрезка массива кусков */
        if(clength != chunks.length) Array.copy(chunks, 0, chunks = new Chunk[clength], 0, clength);
        fldChunks = new ChunkArray(chunks);
        fldObjects = new Object[clength];
    }

    public boolean isSameSource(Source anot) { return anot == this; }

    public boolean contains(ClassType type) { return false; }

    public int length { read = fldObjects.length }

    public final ChunkArray contents { read = fldChunks }

    public final ClassTypeArray declared { read = fldDeclaredArray }

    public final String relativePath { read = fldRelativePath }

    public final Library parentLibrary { read = fldParentLibrary }

    public final Programme parentProgramme { read = fldParentProgramme }

    public final ChunkArray chunks { read = fldChunks }

    public void operator []=(int index, Object component) { fldObjects[index] = component; }

    public Object operator [](int index) { return fldObjects[index]; }

    protected void appendDeclared(ClassType declared) {
        if(declared == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "declared" }));
        }
        fldDeclaredArray.append(declared);
    }
}