/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package java.io;
import malik.emulator.i18n.*;
public class PrintStream extends OutputStream
{
private static final char[] NULL_STR;
static
{
NULL_STR = new char[] {
'n', 'u', 'l', 'l'
};
}
private boolean closed;
private boolean trouble;
private int count;
private char[] cbuf;
private byte[] bbuf;
private PrintListener[] listeners;
private OutputStream stream;
private Object lock;
public PrintStream(OutputStream stream)
{
if(stream == null)
{
throw new NullPointerException("PrintStream: " +
"параметр stream равен нулевой ссылке.");
}
this.cbuf = new char[0x0400];
this.bbuf = new byte[1];
this.stream = stream;
this.lock = new Object();
}
public void close()
{
synchronized(lock)
{
if(!closed)
{
flushStream();
closed = true;
try
{
stream.close();
}
catch(IOException e)
{
invokeSetError();
}
stream = null;
}
}
}
public void flush()
{
synchronized(lock)
{
flushStream();
}
}
public void write(int src)
{
byte[] b;
OutputStream s;
synchronized(lock)
{
if((s = stream) != null)
{
flushStream();
try
{
s.write(src);
}
catch(IOException e)
{
invokeSetError();
}
} else
{
invokeSetError();
}
}
synchronized(cbuf)
{
(b = bbuf)[0] = (byte) src;
notifyListenersWrite(b, 0, 1);
}
}
public void write(byte[] src)
throws IOException
{
int length;
OutputStream s;
if(src == null)
{
throw new NullPointerException("PrintStream.write: " +
"параметр src равен нулевой ссылке.");
}
synchronized(lock)
{
if((s = stream) != null)
{
flushStream();
try
{
s.write(src);
}
catch(IOException e)
{
invokeSetError();
}
} else
{
invokeSetError();
}
}
if((length = src.length) <= 0)
{
return;
}
notifyListenersWrite(src, 0, length);
}
public void write(byte[] src, int offset, int length)
{
int lim;
int len;
OutputStream s;
if(src == null)
{
throw new NullPointerException("PrintStream.write: " +
"параметр src равен нулевой ссылке.");
}
if((lim = offset + length) > (len = src.length) ||
lim < offset || offset > len || offset < 0)
{
throw new ArrayIndexOutOfBoundsException("PrintStream.write: " +
"индекс выходит из диапазона.");
}
synchronized(lock)
{
if((s = stream) != null)
{
flushStream();
try
{
s.write(src, offset, length);
}
catch(IOException e)
{
invokeSetError();
}
} else
{
invokeSetError();
}
}
if(length <= 0)
{
return;
}
notifyListenersWrite(src, offset, length);
}
public void print(boolean src)
{
synchronized(lock)
{
write(src ? "true" : "false", false);
}
}
public void print(char src)
{
synchronized(lock)
{
write(src, false);
}
}
public void print(float src)
{
synchronized(lock)
{
write(Float.toString(src), false);
}
}
public void print(double src)
{
synchronized(lock)
{
write(Double.toString(src), false);
}
}
public void print(int src)
{
synchronized(lock)
{
write(Integer.toString(src), false);
}
}
public void print(long src)
{
synchronized(lock)
{
write(Long.toString(src), false);
}
}
public void print(char[] src)
{
synchronized(lock)
{
write(src, false);
}
}
public void print(String src)
{
synchronized(lock)
{
write(src, false);
}
}
public void print(Object src)
{
synchronized(lock)
{
write(String.valueOf(src), false);
}
}
public void println()
{
synchronized(lock)
{
writeln();
}
}
public void println(boolean src)
{
synchronized(lock)
{
write(src ? "true" : "false", true);
}
}
public void println(char src)
{
synchronized(lock)
{
write(src, true);
}
}
public void println(float src)
{
synchronized(lock)
{
write(Float.toString(src), true);
}
}
public void println(double src)
{
synchronized(lock)
{
write(Double.toString(src), true);
}
}
public void println(int src)
{
synchronized(lock)
{
write(Integer.toString(src), true);
}
}
public void println(long src)
{
synchronized(lock)
{
write(Long.toString(src), true);
}
}
public void println(char[] src)
{
synchronized(lock)
{
write(src, true);
}
}
public void println(String src)
{
synchronized(lock)
{
write(src, true);
}
}
public void println(Object src)
{
synchronized(lock)
{
write(String.valueOf(src), true);
}
}
public boolean checkError()
{
boolean result;
synchronized(lock)
{
if(stream != null)
{
flushStream();
}
result = trouble;
}
return result;
}
public final void addPrintListener(PrintListener listener)
{
int i;
PrintListener[] listeners;
if(listener == null)
{
return;
}
synchronized(cbuf)
{
if((listeners = this.listeners) == null)
{
listeners = this.listeners = new PrintListener[2];
}
if(indexOfListener(listener) < 0)
{
if((i = indexOfListener(null)) < 0)
{
Array.copy(listeners, 0, listeners = this.listeners =
new PrintListener[(i = listeners.length) << 1], 0, i);
}
listeners[i] = listener;
}
}
}
public final void removePrintListener(PrintListener listener)
{
int i;
PrintListener[] listeners;
if(listener == null)
{
return;
}
synchronized(cbuf)
{
if((listeners = this.listeners) != null && (i = indexOfListener(listener)) >= 0)
{
listeners[i] = null;
}
}
}
public final Object getMonitor()
{
return lock;
}
protected void setError()
{
}
protected final void invokeSetError()
{
trouble = true;
try
{
setError();
}
catch(RuntimeException e)
{
/*
* Проигнорировать исключение.
* Выражение вида
* e.printStackTrace();
* может вызвать переполнение стека вызовов.
*/
}
}
private void notifyListenersWrite(byte[] src, int offset, int length)
{
int i;
PrintListener[] listeners;
PrintListener listener;
synchronized(cbuf)
{
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) == null)
{
continue;
}
listener.write(src, offset, length);
}
}
}
private void notifyListenersPrint(char src, boolean newLine)
{
int i;
PrintListener[] listeners;
PrintListener listener;
synchronized(cbuf)
{
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) == null)
{
continue;
}
listener.print(src);
if(!newLine)
{
continue;
}
listener.println();
}
}
}
private void notifyListenersPrint(char[] src, boolean newLine)
{
int i;
PrintListener[] listeners;
PrintListener listener;
synchronized(cbuf)
{
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) == null)
{
continue;
}
listener.print(src);
if(!newLine)
{
continue;
}
listener.println();
}
}
}
private void notifyListenersPrint(String src, boolean newLine)
{
int i;
PrintListener[] listeners;
PrintListener listener;
synchronized(cbuf)
{
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) == null)
{
continue;
}
listener.print(src);
if(!newLine)
{
continue;
}
listener.println();
}
}
}
private void notifyListenersPrintln()
{
int i;
PrintListener[] listeners;
PrintListener listener;
synchronized(cbuf)
{
for(i = (listeners = this.listeners) != null ? listeners.length : 0; i-- > 0; )
{
if((listener = listeners[i]) == null)
{
continue;
}
listener.println();
}
}
}
private void write(char src, boolean newLine)
{
int c;
char[] b;
if(stream != null)
{
if((c = count) > (b = cbuf).length - 3)
{
flushStream();
c = 0;
}
b[c++] = src;
if(newLine)
{
b[c++] = 13;
b[c++] = 10;
}
count = c;
}
notifyListenersPrint(src, newLine);
}
private void write(char[] src, boolean newLine)
{
int c;
int d;
int i;
int r;
int sl;
int bl;
char[] b;
if(src == null)
{
Array.copy(NULL_STR, 0, src = new char[c = NULL_STR.length], 0, c);
}
if(stream != null)
{
if((c = count) > (bl = (b = cbuf).length) - (sl = src.length) - 2)
{
flushStream();
c = 0;
}
for(i = 0; (r = sl - i) > 0; )
{
Array.copy(src, i, b, c, d = Math.min(bl - c, r));
count = (c += d);
if((i += d) < sl)
{
flushStream();
c = 0;
}
}
if(newLine)
{
if(c > bl - 2)
{
flushStream();
c = 0;
}
b[c++] = 13;
b[c++] = 10;
count = c;
}
}
notifyListenersPrint(src, newLine);
}
private void write(String src, boolean newLine)
{
int c;
int d;
int i;
int r;
int sl;
int bl;
char[] b;
if(src == null)
{
src = String.valueOf(src);
}
if(stream != null)
{
if((c = count) > (bl = (b = cbuf).length) - (sl = src.length()) - 2)
{
flushStream();
c = 0;
}
for(i = 0; (r = sl - i) > 0; )
{
src.getChars(i, i + (d = Math.min(bl - c, r)), b, c);
count = (c += d);
if((i += d) < sl)
{
flushStream();
c = 0;
}
}
if(newLine)
{
if(c > bl - 2)
{
flushStream();
c = 0;
}
b[c++] = 13;
b[c++] = 10;
count = c;
}
}
notifyListenersPrint(src, newLine);
}
private void writeln()
{
int c;
char[] b;
if(stream != null)
{
if((c = count) > (b = cbuf).length - 2)
{
flushStream();
c = 0;
}
b[c++] = 13;
b[c++] = 10;
count = c;
}
notifyListenersPrintln();
}
private void flushStream()
{
int c;
OutputStream s;
if((s = stream) != null)
{
try
{
if((c = count) > 0)
{
count = 0;
s.write(Helper.charToByteArray(cbuf, 0, c));
s.flush();
}
}
catch(IOException e)
{
invokeSetError();
}
} else
{
invokeSetError();
}
}
private int indexOfListener(PrintListener listener)
{
int i;
PrintListener[] listeners;
for(i = (listeners = this.listeners).length; i-- > 0; )
{
if(listeners[i] == listener)
{
return i;
}
}
return -1;
}
}