/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.io.cloud;
import java.io.*;
import malik.emulator.io.vfs.*;
import malik.emulator.util.*;
public abstract class HandleOutputStream extends OutputStream
{
private static final int NO_ERROR = 0;
private static final int FILE_NOT_FOUND = 1;
private static final int FILE_UNABLE_TO_CREATE = 2;
private static final int FILE_NAME_NOT_SPECIFIED = 3;
private static final int BUFFER_SIZE = 1 << 9; /* должен быть целой степенью двойки */
private final int openError;
private final int address;
int handle;
int position;
private final byte[] buffer;
private final String fileName;
final DataDescriptor descriptor;
HandleOutputStream(String fileName, int access) {
int h;
int e;
int len;
byte[] buffer;
if(fileName == null || (len = fileName.length()) <= 0)
{
h = 0;
e = FILE_NAME_NOT_SPECIFIED;
} else
{
char[] name;
fileName.getChars(0, len, name = new char[len + 1], 0);
if((h = (int) MalikSystem.syscall(Array.getFirstElementAddress(name), access, 0x0010)) == 0)
{
e = access == 0 || access == 3 ? FILE_NOT_FOUND : FILE_UNABLE_TO_CREATE;
} else
{
e = NO_ERROR;
}
}
if(h == 0)
{
this.openError = e;
this.address = 0;
this.buffer = null;
this.fileName = fileName;
this.descriptor = null;
return;
}
buffer = new byte[BUFFER_SIZE];
this.openError = NO_ERROR;
this.address = Array.getFirstElementAddress(buffer);
this.handle = h;
this.buffer = buffer;
this.fileName = fileName;
this.descriptor = new DataDescriptor();
}
HandleOutputStream(String fileName, DataDescriptor descriptor, int handle) {
byte[] buffer;
if(descriptor == null) descriptor = new DataDescriptor();
buffer = new byte[BUFFER_SIZE];
this.openError = NO_ERROR;
this.address = Array.getFirstElementAddress(buffer);
this.handle = handle;
this.buffer = buffer;
this.fileName = fileName;
this.descriptor = descriptor;
}
public void flush() throws IOException {
int error;
checkOpenError();
error = 0;
synchronized(descriptor)
{
label0:
{
int bufferPosition;
if(handle == 0)
{
error = 1;
break label0;
}
if((bufferPosition = position) > 0)
{
position = 0;
if(!writeFile(bufferPosition))
{
error = 2;
break label0;
}
}
}
}
switch(error)
{
case 1:
throw new ClosedFileException("HandleOutputStream.flush: файловый поток вывода закрыт.");
case 2:
throw new IOException("HandleOutputStream.flush: ошибка произошла при записи файла.");
}
}
public void write(int byteData) throws IOException {
int error;
checkOpenError();
error = 0;
synchronized(descriptor)
{
label0:
{
int bufferPosition;
if(handle == 0)
{
error = 1;
break label0;
}
buffer[bufferPosition = position] = (byte) byteData;
if((position = ++bufferPosition) == BUFFER_SIZE)
{
position = 0;
if(!writeFile(BUFFER_SIZE))
{
error = 2;
break label0;
}
}
}
}
switch(error)
{
case 1:
throw new ClosedFileException("HandleOutputStream.write: файловый поток вывода закрыт.");
case 2:
throw new IOException("HandleOutputStream.write: ошибка произошла при записи файла.");
}
}
public void write(byte[] src, int offset, int length) throws IOException {
int error;
if(src == null)
{
throw new NullPointerException("HandleOutputStream.write: аргумент src равен нулевой ссылке.");
}
Array.checkBound("HandleOutputStream.write", src.length, offset, length);
checkOpenError();
error = 0;
synchronized(descriptor)
{
label0:
{
int bufferPosition;
byte[] bufferContent;
if(handle == 0)
{
error = 1;
break label0;
}
bufferContent = buffer;
bufferPosition = position;
for(int writed; length > 0; offset += writed, length -= writed)
{
int bufferRemainder = BUFFER_SIZE - bufferPosition;
writed = bufferRemainder <= length ? bufferRemainder : length;
Array.copy(src, offset, bufferContent, bufferPosition, writed);
if((bufferPosition += writed) == BUFFER_SIZE)
{
bufferPosition = 0;
if(!writeFile(BUFFER_SIZE))
{
error = 2;
position = 0;
break label0;
}
}
}
position = bufferPosition;
}
}
switch(error)
{
case 1:
throw new ClosedFileException("HandleOutputStream.write: файловый поток вывода закрыт.");
case 2:
throw new IOException("HandleOutputStream.write: ошибка произошла при записи файла.");
}
}
public String toString() {
String name = fileName;
return (handle != 0 ? "Открытый для записи файл " : "Закрытый файл ").concat(name != null && name.length() > 0 ? name : "<имя не задано>");
}
public void checkOpenError() throws IOException {
String name = fileName;
switch(openError)
{
case FILE_NOT_FOUND:
throw new FileNotFoundException((new StringBuilder()).append("HandleOutputStream.checkOpenError: файл ").append(name).append(" не найден или занят.").toString(), name);
case FILE_UNABLE_TO_CREATE:
throw new FileCreationException((new StringBuilder()).append("HandleOutputStream.checkOpenError: не удалось создать файл ").append(name).append('.').toString(), name);
case FILE_NAME_NOT_SPECIFIED:
throw new IOException("HandleOutputStream.checkOpenError: имя файла не было задано при создании этого экземпляра HandleOutputStream.");
}
}
public boolean hasOpenError() {
int e;
return (e = openError) > NO_ERROR && e <= FILE_NAME_NOT_SPECIFIED;
}
public final String getFileName() {
return fileName;
}
final boolean writeFile(int length) {
DataDescriptor descriptor;
(descriptor = this.descriptor).setDataInfo(address, length);
return (int) MalikSystem.syscall(handle, descriptor.getDescriptorAddress(), 0x0013) == length;
}
}