/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package malik.emulator.io.cloud;
import java.io.*;
import malik.emulator.util.*;
public class FileOutputStream extends OutputStream
{
private static final int OPEN_ERROR_NO_ERROR = 0;
private static final int OPEN_ERROR_FILE_NAME_NOT_SPECIFIED = 1;
private static final int OPEN_ERROR_FILE_ACCESS_DENIED = 2;
private int handle;
private int openError;
private Object lock;
private String fileName;
private DataDescriptor descriptor;
public FileOutputStream(String fileName)
{
this(fileName, false);
}
public FileOutputStream(String fileName, boolean appending)
{
int h;
char[] fn;
if(fileName == null || (h = fileName.length()) == 0)
{
this.handle = 0;
this.openError = OPEN_ERROR_FILE_NAME_NOT_SPECIFIED;
this.lock = new Object();
this.fileName = fileName;
this.descriptor = null;
return;
}
fileName.getChars(0, h, fn = new char[h + 1], 0);
if((h = (int) MalikSystem.syscall(Array.getFirstElementAddress(fn),
appending ? 0 : 2, 0x0010)) == 0)
{
this.handle = 0;
this.openError = OPEN_ERROR_FILE_ACCESS_DENIED;
this.lock = new Object();
this.fileName = fileName;
this.descriptor = null;
return;
}
this.handle = h;
this.openError = OPEN_ERROR_NO_ERROR;
this.lock = new Object();
this.fileName = fileName;
this.descriptor = new DataDescriptor();
}
public String toString()
{
return (handle != 0 ? "Открытый для записи файл " : "Закрытый файл ").concat(fileName);
}
public void checkOpenError()
throws IOException
{
switch(openError)
{
default:
if(handle != 0)
{
return;
}
throw new IOException("FileOutputStream: " +
"файл " + fileName + " был закрыт.");
case OPEN_ERROR_FILE_NAME_NOT_SPECIFIED:
throw new IOException("FileOutputStream: " +
"имя файла не задано.");
case OPEN_ERROR_FILE_ACCESS_DENIED:
throw new IOException("FileOutputStream: " +
"файл " + fileName + " недоступен для записи.");
}
}
public boolean hasOpenError()
{
return openError != OPEN_ERROR_NO_ERROR || handle == 0;
}
public final void close()
throws IOException
{
int h;
int error = 0;
synchronized(lock)
{
label0:
{
if((h = handle) == 0)
{
error = 1;
break label0;
}
MalikSystem.syscall((long) h, 0x0011);
handle = 0;
}
}
if(error == 1)
{
throw new IOException("FileOutputStream: " +
"файл " + fileName + " был закрыт.");
}
}
public final void flush()
throws IOException
{
}
public final void write(int src)
throws IOException
{
synchronized(lock)
{
checkOpenError();
descriptor.setDataInfo(MalikSystem.getLocalVariableAddress(src), 1);
writeFile();
}
}
public final void write(byte[] src)
throws IOException
{
int length;
if(src == null)
{
throw new NullPointerException("FileOutputStream.write: " +
"параметр src равен нулевой ссылке.");
}
synchronized(lock)
{
checkOpenError();
if((length = src.length) > 0)
{
descriptor.setDataInfo(src, 0, length);
writeFile();
}
}
}
public final void write(byte[] src, int offset, int length)
throws IOException
{
int lim;
int len;
if(src == null)
{
throw new NullPointerException("FileOutputStream.write: " +
"параметр src равен нулевой ссылке.");
}
if((lim = offset + length) > (len = src.length) ||
lim < offset || offset > len || offset < 0)
{
throw new ArrayIndexOutOfBoundsException("FileOutputStream.write: " +
"индекс выходит из диапазона.");
}
synchronized(lock)
{
checkOpenError();
if(length > 0)
{
descriptor.setDataInfo(src, offset, length);
writeFile();
}
}
}
public final String getFileName()
{
return fileName;
}
protected void $finalize$()
{
int h;
if((h = handle) != 0)
{
MalikSystem.syscall((long) h, 0x0011);
handle = 0;
}
}
private void writeFile()
throws InterruptedIOException
{
int required;
int writed;
DataDescriptor d = descriptor;
writed = (int) MalikSystem.syscall(handle, d.getDescriptorAddress(), 0x0013);
required = d.getLength();
if(writed < required)
{
throw new InterruptedIOException("FileOutputStream.write: " +
"процесс записи в файл " + fileName +
" был прерван. Записано байт: " + writed +
" из " + required + ".", writed);
}
}
}