/*
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
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);
}
}