/*
Реализация спецификаций 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.*;
import malik.emulator.io.vfs.*;
import malik.emulator.time.*;
import malik.emulator.util.*;
public final class CloudFileSystem extends Object implements VirtualFileSystemReadOnly, VirtualFileSystemReadWrite
{
public static final CloudFileSystem instance;
static {
instance = new CloudFileSystem();
}
static long computeFields(long time) {
return CalendarSystem.gregorian.computeFields(time, 0);
}
static long computeTime(long fields) {
return CalendarSystem.gregorian.computeTime(fields, 0);
}
private CloudFileSystem() {
}
public String toString() {
return "Файловая система приложения";
}
public void readAttributes(String objectName, FileAttributes objectAttr) throws IOException {
int len;
char[] name;
AttributesDescriptor d;
if(objectName == null)
{
throw new NullPointerException("CloudFileSystem.readAttributes: аргумент objectName равен нулевой ссылке.");
}
d = new AttributesDescriptor();
objectName.getChars(0, len = objectName.length(), name = new char[len + 1], 0);
if(MalikSystem.syscall(Array.getFirstElementAddress(name), d.getDescriptorAddress(), 0x001c) == 0L)
{
throw new ObjectNotFoundException((new StringBuilder()).append("CloudFileSystem.readAttributes: объект ").append(objectName).append(" не найден.").toString(), objectName);
}
if(objectAttr != null) objectAttr.setAttributes(d.attributes, computeTime(d.timeOfCreation), computeTime(d.timeOfLastWrite), computeTime(d.timeOfLastAccess));
}
public int getObjectNameMaximumLength() throws IOException {
return (int) MalikSystem.syscall(0L, 0x0016);
}
public FileEnumeration findFirst() throws IOException {
int h;
int len;
char[] directory = new char[] { '/', '\0' };
char[] name = new char[len = getObjectNameMaximumLength() + 1];
FileInfoDescriptor d = new FileInfoDescriptor(len, Array.getFirstElementAddress(name));
return (h = (int) MalikSystem.syscall(Array.getFirstElementAddress(directory), d.getDescriptorAddress(), 0x0018)) > 0 ? new CloudFileEnumeration(h, name, d) : null;
}
public FileEnumeration findFirst(String objectName) throws IOException {
int h;
int lim;
int len;
char[] name;
char[] directory;
FileInfoDescriptor d;
if(objectName == null)
{
throw new NullPointerException("CloudFileSystem.findFirst: аргумент objectName равен нулевой ссылке.");
}
name = new char[len = getObjectNameMaximumLength() + 1];
d = new FileInfoDescriptor(len, Array.getFirstElementAddress(name));
if(!objectName.startsWith("/")) objectName = "/".concat(objectName);
lim = (len = objectName.length()) - 1;
if(len > 0 && objectName.charAt(lim) != '/')
{
objectName.getChars(0, len, directory = new char[len + 1], 0);
return (h = (int) MalikSystem.syscall(Array.getFirstElementAddress(directory), d.getDescriptorAddress(), 0x0018)) > 0 ? new CloudFileEnumeration(h, name, d) : null;
}
if(len > 1)
{
objectName.getChars(0, lim, directory = new char[len], 0);
if(MalikSystem.syscall(Array.getFirstElementAddress(directory), d.getDescriptorAddress(), 0x001c) == 0L || (d.attributes & FileAttributes.DIRECTORY) == 0)
{
throw new DirectoryNotFoundException((new StringBuilder()).append("CloudFileSystem.findFirst: папка ").append(objectName).append(" не найдена.").toString(), objectName);
}
}
objectName.getChars(0, len, directory = new char[len + 1], 0);
return (h = (int) MalikSystem.syscall(Array.getFirstElementAddress(directory), d.getDescriptorAddress(), 0x0018)) > 0 ? new CloudFileEnumeration(h, name, d) : null;
}
public InputStream openFileForRead(String fileName) throws IOException {
int h;
int len;
char[] name;
if(fileName == null)
{
throw new NullPointerException("CloudFileSystem.openFileForRead: аргумент fileName равен нулевой ссылке.");
}
if((len = fileName.length()) <= 0)
{
throw new IllegalArgumentException("CloudFileSystem.openFileForRead: аргумент fileName является пустой строкой.");
}
fileName.getChars(0, len, name = new char[len + 1], 0);
if((h = (int) MalikSystem.syscall(Array.getFirstElementAddress(name), 0x01, 0x0010)) == 0)
{
throw new FileNotFoundException((new StringBuilder()).append("CloudFileSystem.openFileForRead: файл ").append(fileName).append(" не найден или занят.").toString(), fileName);
}
return new FileInputStream(fileName, h);
}
public void writeAttributes(String objectName, FileAttributes objectAttr) throws IOException {
int len;
char[] name;
AttributesDescriptor d;
if(objectName == null)
{
throw new NullPointerException("CloudFileSystem.writeAttributes: аргумент objectName равен нулевой ссылке.");
}
if(objectAttr == null)
{
throw new NullPointerException("CloudFileSystem.writeAttributes: аргумент objectAttr равен нулевой ссылке.");
}
objectName.getChars(0, len = objectName.length(), name = new char[len + 1], 0);
(d = new AttributesDescriptor()).attributes = objectAttr.getAttributes() & ~FileAttributes.DIRECTORY;
d.timeOfCreation = computeFields(objectAttr.getCreationTime());
d.timeOfLastWrite = computeFields(objectAttr.getLastWriteTime());
d.timeOfLastAccess = computeFields(objectAttr.getLastAccessTime());
if(MalikSystem.syscall(Array.getFirstElementAddress(name), d.getDescriptorAddress(), 0x001d) == 0L)
{
throw new ObjectNotFoundException((new StringBuilder()).append("CloudFileSystem.writeAttributes: объект ").append(objectName).append(" не найден.").toString(), objectName);
}
}
public void move(String oldObjectName, String newObjectName) throws IOException {
int len;
char[] oldName;
char[] newName;
if(oldObjectName == null)
{
throw new NullPointerException("CloudFileSystem.move: аргумент oldObjectName равен нулевой ссылке.");
}
if(newObjectName == null)
{
throw new NullPointerException("CloudFileSystem.move: аргумент newObjectName равен нулевой ссылке.");
}
oldObjectName.getChars(0, len = oldObjectName.length(), oldName = new char[len + 1], 0);
newObjectName.getChars(0, len = newObjectName.length(), newName = new char[len + 1], 0);
if(MalikSystem.syscall(Array.getFirstElementAddress(oldName), Array.getFirstElementAddress(newName), 0x001b) == 0L)
{
throw new MoveOperationException("CloudFileSystem.move: не удалось выполнить перемещение и/или переименование объекта.", oldObjectName, newObjectName);
}
}
public void deleteDirectory(String directoryName) throws IOException {
int len;
char[] name;
AttributesDescriptor d;
if(directoryName == null)
{
throw new NullPointerException("CloudFileSystem.deleteDirectory: аргумент directoryName равен нулевой ссылке.");
}
d = new AttributesDescriptor();
directoryName.getChars(0, len = directoryName.length(), name = new char[len + 1], 0);
if(MalikSystem.syscall(Array.getFirstElementAddress(name), d.getDescriptorAddress(), 0x001c) == 0L || (d.attributes & FileAttributes.DIRECTORY) == 0)
{
throw new DirectoryNotFoundException((new StringBuilder()).append("CloudFileSystem.deleteDirectory: папка ").append(directoryName).append(" не найдена.").toString(), directoryName);
}
if(MalikSystem.syscall((long) Array.getFirstElementAddress(name), 0x001f) == 0L)
{
throw new DirectoryDeletionException(
(new StringBuilder()).append("CloudFileSystem.deleteDirectory: не удалось удалить папку ").append(directoryName).append('.').toString(), directoryName
);
}
}
public void deleteFile(String fileName) throws IOException {
int len;
char[] name;
AttributesDescriptor d;
if(fileName == null)
{
throw new NullPointerException("CloudFileSystem.deleteFile: аргумент fileName равен нулевой ссылке.");
}
d = new AttributesDescriptor();
fileName.getChars(0, len = fileName.length(), name = new char[len + 1], 0);
if(MalikSystem.syscall(Array.getFirstElementAddress(name), d.getDescriptorAddress(), 0x001c) == 0L || (d.attributes & FileAttributes.DIRECTORY) != 0)
{
throw new FileNotFoundException((new StringBuilder()).append("CloudFileSystem.deleteFile: файл ").append(fileName).append(" не найден.").toString(), fileName);
}
if(MalikSystem.syscall((long) Array.getFirstElementAddress(name), 0x0017) == 0L)
{
throw new FileDeletionException((new StringBuilder()).append("CloudFileSystem.deleteFile: не удалось удалить файл ").append(fileName).append('.').toString(), fileName);
}
}
public void createDirectory(String directoryName) throws IOException {
int len;
char[] name;
if(directoryName == null)
{
throw new NullPointerException("CloudFileSystem.createDirectory: аргумент directoryName равен нулевой ссылке.");
}
directoryName.getChars(0, len = directoryName.length(), name = new char[len + 1], 0);
if(MalikSystem.syscall((long) Array.getFirstElementAddress(name), 0x001e) == 0L)
{
throw new DirectoryCreationException(
(new StringBuilder()).append("CloudFileSystem.createDirectory: не удалось создать папку ").append(directoryName).append('.').toString(), directoryName
);
}
}
public OutputStream createFile(String fileName) throws IOException {
int h;
int len;
char[] name;
if(fileName == null)
{
throw new NullPointerException("CloudFileSystem.createFile: аргумент fileName равен нулевой ссылке.");
}
if((len = fileName.length()) <= 0)
{
throw new IllegalArgumentException("CloudFileSystem.createFile: аргумент fileName является пустой строкой.");
}
fileName.getChars(0, len, name = new char[len + 1], 0);
if((h = (int) MalikSystem.syscall(Array.getFirstElementAddress(name), 0x02, 0x0010)) == 0)
{
throw new FileCreationException((new StringBuilder()).append("CloudFileSystem.createFile: не удалось создать файл ").append(fileName).append('.').toString(), fileName);
}
return new FileOutputStream(fileName, h);
}
public OutputStream openFileForAppend(String fileName) throws IOException {
int h;
int len;
char[] name;
if(fileName == null)
{
throw new NullPointerException("CloudFileSystem.openFileForAppending: аргумент fileName равен нулевой ссылке.");
}
if((len = fileName.length()) <= 0)
{
throw new IllegalArgumentException("CloudFileSystem.openFileForAppending: аргумент fileName является пустой строкой.");
}
fileName.getChars(0, len, name = new char[len + 1], 0);
if((h = (int) MalikSystem.syscall(Array.getFirstElementAddress(name), 0x00, 0x0010)) == 0)
{
throw new FileNotFoundException((new StringBuilder()).append("CloudFileSystem.openFileForAppending: файл ").append(fileName).append(" не найден или занят.").toString(), fileName);
}
return new FileOutputStream(fileName, h);
}
public IOStream openFileForReadWrite(String fileName) throws IOException {
int h;
int len;
char[] name;
if(fileName == null)
{
throw new NullPointerException("CloudFileSystem.openFileForReadWrite: аргумент fileName равен нулевой ссылке.");
}
if((len = fileName.length()) <= 0)
{
throw new IllegalArgumentException("CloudFileSystem.openFileForReadWrite: аргумент fileName является пустой строкой.");
}
fileName.getChars(0, len, name = new char[len + 1], 0);
if((h = (int) MalikSystem.syscall(Array.getFirstElementAddress(name), 0x03, 0x0010)) == 0)
{
throw new FileNotFoundException((new StringBuilder()).append("CloudFileSystem.openFileForReadWrite: файл ").append(fileName).append(" не найден или занят.").toString(), fileName);
}
return new FileIOStream(fileName, h);
}
}
class AttributesDescriptor extends SystemDescriptor
{
/*
* время в формате 0xггггммддччммсссс
* биты 48-63: год (1-65535)
* биты 40-47: месяц (1-12)
* биты 32-39: число (1-31)
* биты 24-31: час (0-23)
* биты 16-23: минута (0-59)
* биты 00-15: миллисекунда (0-59999)
*/
public long timeOfCreation;
public long timeOfLastAccess;
public long timeOfLastWrite;
public int attributes;
public int reserved0;
public AttributesDescriptor() {
}
}
class FileInfoDescriptor extends AttributesDescriptor
{
public long size;
public int nameLength;
public int nameAddress;
public FileInfoDescriptor(int nameLength, int nameAddress) {
this.nameLength = nameLength;
this.nameAddress = nameAddress;
}
}
final class CloudFileEnumeration extends FileEnumeration
{
private int handle;
private final char[] objectName;
private final FileInfoDescriptor descriptor;
public CloudFileEnumeration(int handle, char[] objectName, FileInfoDescriptor descriptor) {
this.handle = handle;
this.objectName = objectName;
this.descriptor = descriptor;
setAttributes(objectName, descriptor);
}
public void close() throws IOException {
synchronized(descriptor)
{
closeHandle();
}
}
public boolean findNext() throws IOException {
boolean result;
int error = 0;
FileInfoDescriptor d;
synchronized(d = descriptor)
{
label0:
{
int h;
if((h = handle) == 0)
{
error = 1;
result = false;
break label0;
}
if(MalikSystem.syscall(h, d.getDescriptorAddress(), 0x0019) != 1L)
{
result = false;
break label0;
}
setAttributes(objectName, d);
result = true;
}
}
if(error == 1)
{
throw new ClosedEnumerationException("FileEnumeration.findNext: перечисление файлов закрыто.");
}
return result;
}
protected void $finalize$() {
closeHandle();
}
private void closeHandle() {
int h;
if((h = handle) != 0)
{
MalikSystem.syscall((long) h, 0x001a);
handle = 0;
}
}
private void setAttributes(char[] f, FileInfoDescriptor d) {
setAttributes(
d.attributes, CloudFileSystem.computeTime(d.timeOfCreation), CloudFileSystem.computeTime(d.timeOfLastWrite), CloudFileSystem.computeTime(d.timeOfLastAccess), d.size,
new String(f, 0, Array.findf(f, 0, 0))
);
}
}