/*
Реализация спецификаций 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.fileformats.text.mapped;
import java.io.*;
import malik.emulator.fileformats.*;
public class ManifestFile extends CustomKeyValueList
implements AttributableMappedTextDecoder
{
public static final char KEY_VALUE_SEPARATOR = ':';
public static final char ATTRIBUTES_SEPARATOR = ',';
/* Условие выхода из этого метода:
* c != 10 && c != 13
* где c = s[i], i - возвращаемое значение метода. */
private static int skipLineEndings(byte[] stream, int offset)
{
int c;
int i = offset;
for(; (c = stream[i]) == 10 || c == 13; i += c == 13 && stream[i + 1] == 10 ? 2 : 1);
return i;
}
private String key;
private String value;
public ManifestFile()
{
}
public void loadFromInputStream(InputStream stream)
throws IOException, InvalidDataFormatException
{
int i;
int size;
byte[] s;
stream.read(s = new byte[(size = stream.available()) + 1], 0, size);
clear();
try
{
i = size >= 3 && s[0] == ((byte) 0xef) && s[1] == ((byte) 0xbb) &&
s[2] == ((byte) 0xbf) ? 3 : 0;
for(; s[i = skipLineEndings(s, i)] != 0 && i < size; set(key, value))
{
if(s[i = parseKey(s, i)] != KEY_VALUE_SEPARATOR)
{
throw new InvalidDataFormatException(
"Неправильный формат MANIFEST-файла.");
}
i = parseValue(s, i + 1);
}
}
finally
{
key = null;
value = null;
}
}
public void loadFromInputStream(InputStream stream, String encoding)
throws IOException, InvalidDataFormatException, UnsupportedEncodingException
{
loadFromInputStream(stream);
}
public void loadFromDataStream(DataInputStream stream)
throws IOException, InvalidDataFormatException
{
loadFromInputStream(stream);
}
public void loadFromDataStream(DataInputStream stream, String encoding)
throws IOException, InvalidDataFormatException, UnsupportedEncodingException
{
loadFromInputStream(stream);
}
public String[] getAttributes(String key)
{
int i;
int j;
int len;
int index;
int length;
String[] result;
String val;
if((val = get(key)) == null)
{
return null;
}
if((length = (val = val.trim()).length()) == 0)
{
return new String[0];
}
for(len = 1, j = length; j-- > 0; )
{
if(val.charAt(j) == ATTRIBUTES_SEPARATOR)
{
len++;
}
}
for(result = new String[len], j = i = index = 0; j <= length; j++)
{
if(j == length || val.charAt(j) == ATTRIBUTES_SEPARATOR)
{
result[index++] = val.substring(i, j).trim().intern();
i = j + 1;
}
}
return result;
}
private int parseKey(byte[] stream, int offset)
throws InvalidDataFormatException
{
int c;
int i = offset;
if(((c = stream[i++]) < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z'))
{
throw new InvalidDataFormatException(
"Неправильный формат MANIFEST-файла.");
}
for(; ((c = stream[i]) >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') || c == '-' || c == '_'; i++);
key = (new String(stream, offset, i - offset)).intern();
return i;
}
private int parseValue(byte[] stream, int offset)
{
int c;
int i = offset;
ByteArrayOutputStream result;
if(stream[i] == 32)
{
offset = ++i;
}
result = new ByteArrayOutputStream();
do
{
for(; (c = stream[i]) != 0 && c != 10 && c != 13; i++);
result.write(stream, offset, i - offset);
if(c == 0)
{
break;
}
i += c == 13 && stream[i + 1] == 10 ? 2 : 1;
if((c = stream[i]) != 32)
{
break;
}
offset = ++i;
} while(true);
value = result.toString().intern();
return i;
}
}