544 lines
19 KiB
Java
544 lines
19 KiB
Java
|
package okhttp3.internal.http2;
|
||
|
|
||
|
import java.io.Closeable;
|
||
|
import java.io.EOFException;
|
||
|
import java.io.IOException;
|
||
|
import java.util.List;
|
||
|
import java.util.logging.Level;
|
||
|
import java.util.logging.Logger;
|
||
|
import o.C14953gcr;
|
||
|
import o.C14957gcv;
|
||
|
import o.C15111ghZ;
|
||
|
import o.C15139giB;
|
||
|
import o.C15155gij;
|
||
|
import o.InterfaceC15149gid;
|
||
|
import o.gdP;
|
||
|
import o.giD;
|
||
|
import okhttp3.internal.Util;
|
||
|
import okhttp3.internal.http2.Hpack;
|
||
|
|
||
|
/* loaded from: classes.dex */
|
||
|
public final class Http2Reader implements Closeable {
|
||
|
public static final Companion Companion = new Companion(null);
|
||
|
private static final Logger logger;
|
||
|
private final boolean client;
|
||
|
private final ContinuationSource continuation;
|
||
|
private final Hpack.Reader hpackReader;
|
||
|
private final InterfaceC15149gid source;
|
||
|
|
||
|
/* loaded from: classes.dex */
|
||
|
public interface Handler {
|
||
|
void ackSettings();
|
||
|
|
||
|
void alternateService(int i, String str, C15155gij c15155gij, String str2, int i2, long j);
|
||
|
|
||
|
void data(boolean z, int i, InterfaceC15149gid interfaceC15149gid, int i2) throws IOException;
|
||
|
|
||
|
void goAway(int i, ErrorCode errorCode, C15155gij c15155gij);
|
||
|
|
||
|
void headers(boolean z, int i, int i2, List<Header> list);
|
||
|
|
||
|
void ping(boolean z, int i, int i2);
|
||
|
|
||
|
void priority(int i, int i2, int i3, boolean z);
|
||
|
|
||
|
void pushPromise(int i, int i2, List<Header> list) throws IOException;
|
||
|
|
||
|
void rstStream(int i, ErrorCode errorCode);
|
||
|
|
||
|
void settings(boolean z, Settings settings);
|
||
|
|
||
|
void windowUpdate(int i, long j);
|
||
|
}
|
||
|
|
||
|
public Http2Reader(InterfaceC15149gid interfaceC15149gid, boolean z) {
|
||
|
C14957gcv.e(interfaceC15149gid, "");
|
||
|
this.source = interfaceC15149gid;
|
||
|
this.client = z;
|
||
|
ContinuationSource continuationSource = new ContinuationSource(interfaceC15149gid);
|
||
|
this.continuation = continuationSource;
|
||
|
this.hpackReader = new Hpack.Reader(continuationSource, 4096, 0, 4, null);
|
||
|
}
|
||
|
|
||
|
public final void readConnectionPreface(Handler handler) throws IOException {
|
||
|
C14957gcv.e(handler, "");
|
||
|
if (this.client) {
|
||
|
if (!nextFrame(true, handler)) {
|
||
|
throw new IOException("Required SETTINGS preface not received");
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
C15155gij c = this.source.c(Http2.CONNECTION_PREFACE.a());
|
||
|
Logger logger2 = logger;
|
||
|
if (logger2.isLoggable(Level.FINE)) {
|
||
|
logger2.fine(Util.format(C14957gcv.c("<< CONNECTION ", (Object) c.c()), new Object[0]));
|
||
|
}
|
||
|
if (C14957gcv.b(Http2.CONNECTION_PREFACE, c)) {
|
||
|
return;
|
||
|
}
|
||
|
String str = c.d;
|
||
|
if (str == null) {
|
||
|
byte[] b = c.b();
|
||
|
C14957gcv.e(b, "");
|
||
|
String str2 = new String(b, gdP.a);
|
||
|
c.d = str2;
|
||
|
str = str2;
|
||
|
}
|
||
|
throw new IOException(C14957gcv.c("Expected a connection header but was ", (Object) str));
|
||
|
}
|
||
|
|
||
|
public final boolean nextFrame(boolean z, Handler handler) throws IOException {
|
||
|
C14957gcv.e(handler, "");
|
||
|
try {
|
||
|
this.source.g(9L);
|
||
|
int readMedium = Util.readMedium(this.source);
|
||
|
if (readMedium > 16384) {
|
||
|
throw new IOException(C14957gcv.c("FRAME_SIZE_ERROR: ", Integer.valueOf(readMedium)));
|
||
|
}
|
||
|
int and = Util.and(this.source.f(), 255);
|
||
|
int and2 = Util.and(this.source.f(), 255);
|
||
|
int n = this.source.n() & Integer.MAX_VALUE;
|
||
|
Logger logger2 = logger;
|
||
|
if (logger2.isLoggable(Level.FINE)) {
|
||
|
logger2.fine(Http2.INSTANCE.frameLog(true, n, readMedium, and, and2));
|
||
|
}
|
||
|
if (z && and != 4) {
|
||
|
throw new IOException(C14957gcv.c("Expected a SETTINGS frame but was ", (Object) Http2.INSTANCE.formattedType$okhttp(and)));
|
||
|
}
|
||
|
switch (and) {
|
||
|
case 0:
|
||
|
readData(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 1:
|
||
|
readHeaders(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 2:
|
||
|
readPriority(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 3:
|
||
|
readRstStream(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 4:
|
||
|
readSettings(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 5:
|
||
|
readPushPromise(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 6:
|
||
|
readPing(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 7:
|
||
|
readGoAway(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
case 8:
|
||
|
readWindowUpdate(handler, readMedium, and2, n);
|
||
|
return true;
|
||
|
default:
|
||
|
this.source.j(readMedium);
|
||
|
return true;
|
||
|
}
|
||
|
} catch (EOFException unused) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private final void readHeaders(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i3 == 0) {
|
||
|
throw new IOException("PROTOCOL_ERROR: TYPE_HEADERS streamId == 0");
|
||
|
}
|
||
|
boolean z = (i2 & 1) != 0;
|
||
|
int and = (i2 & 8) != 0 ? Util.and(this.source.f(), 255) : 0;
|
||
|
if ((i2 & 32) != 0) {
|
||
|
readPriority(handler, i3);
|
||
|
i -= 5;
|
||
|
}
|
||
|
handler.headers(z, i3, -1, readHeaderBlock(Companion.lengthWithoutPadding(i, i2, and), and, i2, i3));
|
||
|
}
|
||
|
|
||
|
private final List<Header> readHeaderBlock(int i, int i2, int i3, int i4) throws IOException {
|
||
|
this.continuation.setLeft(i);
|
||
|
ContinuationSource continuationSource = this.continuation;
|
||
|
continuationSource.setLength(continuationSource.getLeft());
|
||
|
this.continuation.setPadding(i2);
|
||
|
this.continuation.setFlags(i3);
|
||
|
this.continuation.setStreamId(i4);
|
||
|
this.hpackReader.readHeaders();
|
||
|
return this.hpackReader.getAndResetHeaderList();
|
||
|
}
|
||
|
|
||
|
private final void readData(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i3 == 0) {
|
||
|
throw new IOException("PROTOCOL_ERROR: TYPE_DATA streamId == 0");
|
||
|
}
|
||
|
boolean z = (i2 & 1) != 0;
|
||
|
if ((i2 & 32) != 0) {
|
||
|
throw new IOException("PROTOCOL_ERROR: FLAG_COMPRESSED without SETTINGS_COMPRESS_DATA");
|
||
|
}
|
||
|
int and = (i2 & 8) != 0 ? Util.and(this.source.f(), 255) : 0;
|
||
|
handler.data(z, i3, this.source, Companion.lengthWithoutPadding(i, i2, and));
|
||
|
this.source.j(and);
|
||
|
}
|
||
|
|
||
|
private final void readPriority(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i == 5) {
|
||
|
if (i3 == 0) {
|
||
|
throw new IOException("TYPE_PRIORITY streamId == 0");
|
||
|
}
|
||
|
readPriority(handler, i3);
|
||
|
} else {
|
||
|
StringBuilder sb = new StringBuilder("TYPE_PRIORITY length: ");
|
||
|
sb.append(i);
|
||
|
sb.append(" != 5");
|
||
|
throw new IOException(sb.toString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private final void readPriority(Handler handler, int i) throws IOException {
|
||
|
int n = this.source.n();
|
||
|
handler.priority(i, n & Integer.MAX_VALUE, Util.and(this.source.f(), 255) + 1, (Integer.MIN_VALUE & n) != 0);
|
||
|
}
|
||
|
|
||
|
private final void readRstStream(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i != 4) {
|
||
|
StringBuilder sb = new StringBuilder("TYPE_RST_STREAM length: ");
|
||
|
sb.append(i);
|
||
|
sb.append(" != 4");
|
||
|
throw new IOException(sb.toString());
|
||
|
}
|
||
|
if (i3 == 0) {
|
||
|
throw new IOException("TYPE_RST_STREAM streamId == 0");
|
||
|
}
|
||
|
int n = this.source.n();
|
||
|
ErrorCode fromHttp2 = ErrorCode.Companion.fromHttp2(n);
|
||
|
if (fromHttp2 == null) {
|
||
|
throw new IOException(C14957gcv.c("TYPE_RST_STREAM unexpected error code: ", Integer.valueOf(n)));
|
||
|
}
|
||
|
handler.rstStream(i3, fromHttp2);
|
||
|
}
|
||
|
|
||
|
/* JADX WARN: Code restructure failed: missing block: B:32:0x007e, code lost:
|
||
|
|
||
|
throw new java.io.IOException(o.C14957gcv.c("PROTOCOL_ERROR SETTINGS_MAX_FRAME_SIZE: ", java.lang.Integer.valueOf(r4)));
|
||
|
*/
|
||
|
/*
|
||
|
Code decompiled incorrectly, please refer to instructions dump.
|
||
|
To view partially-correct add '--show-bad-code' argument
|
||
|
*/
|
||
|
private final void readSettings(okhttp3.internal.http2.Http2Reader.Handler r8, int r9, int r10, int r11) throws java.io.IOException {
|
||
|
/*
|
||
|
r7 = this;
|
||
|
if (r11 != 0) goto Lb5
|
||
|
r11 = 1
|
||
|
r10 = r10 & r11
|
||
|
if (r10 == 0) goto L14
|
||
|
if (r9 != 0) goto Lc
|
||
|
r8.ackSettings()
|
||
|
return
|
||
|
Lc:
|
||
|
java.io.IOException r8 = new java.io.IOException
|
||
|
java.lang.String r9 = "FRAME_SIZE_ERROR ack frame should be empty!"
|
||
|
r8.<init>(r9)
|
||
|
throw r8
|
||
|
L14:
|
||
|
int r10 = r9 % 6
|
||
|
if (r10 != 0) goto La5
|
||
|
okhttp3.internal.http2.Settings r10 = new okhttp3.internal.http2.Settings
|
||
|
r10.<init>()
|
||
|
r0 = -2147483648(0xffffffff80000000, float:-0.0)
|
||
|
r1 = 0
|
||
|
if (r9 > r0) goto L29
|
||
|
o.gde$LWm r9 = o.C14973gde.c
|
||
|
o.gde r9 = o.C14973gde.e()
|
||
|
goto L30
|
||
|
L29:
|
||
|
o.gde r0 = new o.gde
|
||
|
int r9 = r9 - r11
|
||
|
r0.<init>(r1, r9)
|
||
|
r9 = r0
|
||
|
L30:
|
||
|
o.gda r9 = (o.C14969gda) r9
|
||
|
r0 = 6
|
||
|
o.gda r9 = o.C14977gdi.b(r9, r0)
|
||
|
int r0 = r9.b
|
||
|
int r2 = r9.d
|
||
|
int r9 = r9.e
|
||
|
if (r9 <= 0) goto L41
|
||
|
if (r0 <= r2) goto L45
|
||
|
L41:
|
||
|
if (r9 >= 0) goto La1
|
||
|
if (r2 > r0) goto La1
|
||
|
L45:
|
||
|
o.gid r3 = r7.source
|
||
|
short r3 = r3.s()
|
||
|
r4 = 65535(0xffff, float:9.1834E-41)
|
||
|
int r3 = okhttp3.internal.Util.and(r3, r4)
|
||
|
o.gid r4 = r7.source
|
||
|
int r4 = r4.n()
|
||
|
r5 = 2
|
||
|
if (r3 == r5) goto L8d
|
||
|
r5 = 3
|
||
|
r6 = 4
|
||
|
if (r3 == r5) goto L8b
|
||
|
if (r3 == r6) goto L7f
|
||
|
r5 = 5
|
||
|
if (r3 == r5) goto L65
|
||
|
goto L9a
|
||
|
L65:
|
||
|
r5 = 16384(0x4000, float:2.2959E-41)
|
||
|
if (r4 < r5) goto L6f
|
||
|
r5 = 16777215(0xffffff, float:2.3509886E-38)
|
||
|
if (r4 > r5) goto L6f
|
||
|
goto L9a
|
||
|
L6f:
|
||
|
java.io.IOException r8 = new java.io.IOException
|
||
|
java.lang.String r9 = "PROTOCOL_ERROR SETTINGS_MAX_FRAME_SIZE: "
|
||
|
java.lang.Integer r10 = java.lang.Integer.valueOf(r4)
|
||
|
java.lang.String r9 = o.C14957gcv.c(r9, r10)
|
||
|
r8.<init>(r9)
|
||
|
throw r8
|
||
|
L7f:
|
||
|
if (r4 < 0) goto L83
|
||
|
r3 = 7
|
||
|
goto L9a
|
||
|
L83:
|
||
|
java.io.IOException r8 = new java.io.IOException
|
||
|
java.lang.String r9 = "PROTOCOL_ERROR SETTINGS_INITIAL_WINDOW_SIZE > 2^31 - 1"
|
||
|
r8.<init>(r9)
|
||
|
throw r8
|
||
|
L8b:
|
||
|
r3 = r6
|
||
|
goto L9a
|
||
|
L8d:
|
||
|
if (r4 == 0) goto L9a
|
||
|
if (r4 != r11) goto L92
|
||
|
goto L9a
|
||
|
L92:
|
||
|
java.io.IOException r8 = new java.io.IOException
|
||
|
java.lang.String r9 = "PROTOCOL_ERROR SETTINGS_ENABLE_PUSH != 0 or 1"
|
||
|
r8.<init>(r9)
|
||
|
throw r8
|
||
|
L9a:
|
||
|
r10.set(r3, r4)
|
||
|
if (r0 == r2) goto La1
|
||
|
int r0 = r0 + r9
|
||
|
goto L45
|
||
|
La1:
|
||
|
r8.settings(r1, r10)
|
||
|
return
|
||
|
La5:
|
||
|
java.io.IOException r8 = new java.io.IOException
|
||
|
java.lang.String r10 = "TYPE_SETTINGS length % 6 != 0: "
|
||
|
java.lang.Integer r9 = java.lang.Integer.valueOf(r9)
|
||
|
java.lang.String r9 = o.C14957gcv.c(r10, r9)
|
||
|
r8.<init>(r9)
|
||
|
throw r8
|
||
|
Lb5:
|
||
|
java.io.IOException r8 = new java.io.IOException
|
||
|
java.lang.String r9 = "TYPE_SETTINGS streamId != 0"
|
||
|
r8.<init>(r9)
|
||
|
throw r8
|
||
|
*/
|
||
|
throw new UnsupportedOperationException("Method not decompiled: okhttp3.internal.http2.Http2Reader.readSettings(okhttp3.internal.http2.Http2Reader$Handler, int, int, int):void");
|
||
|
}
|
||
|
|
||
|
private final void readPushPromise(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i3 == 0) {
|
||
|
throw new IOException("PROTOCOL_ERROR: TYPE_PUSH_PROMISE streamId == 0");
|
||
|
}
|
||
|
int and = (i2 & 8) != 0 ? Util.and(this.source.f(), 255) : 0;
|
||
|
handler.pushPromise(i3, Integer.MAX_VALUE & this.source.n(), readHeaderBlock(Companion.lengthWithoutPadding(i - 4, i2, and), and, i2, i3));
|
||
|
}
|
||
|
|
||
|
private final void readPing(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i != 8) {
|
||
|
throw new IOException(C14957gcv.c("TYPE_PING length != 8: ", Integer.valueOf(i)));
|
||
|
}
|
||
|
if (i3 != 0) {
|
||
|
throw new IOException("TYPE_PING streamId != 0");
|
||
|
}
|
||
|
handler.ping((i2 & 1) != 0, this.source.n(), this.source.n());
|
||
|
}
|
||
|
|
||
|
private final void readGoAway(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i < 8) {
|
||
|
throw new IOException(C14957gcv.c("TYPE_GOAWAY length < 8: ", Integer.valueOf(i)));
|
||
|
}
|
||
|
if (i3 != 0) {
|
||
|
throw new IOException("TYPE_GOAWAY streamId != 0");
|
||
|
}
|
||
|
int n = this.source.n();
|
||
|
int n2 = this.source.n();
|
||
|
int i4 = i - 8;
|
||
|
ErrorCode fromHttp2 = ErrorCode.Companion.fromHttp2(n2);
|
||
|
if (fromHttp2 == null) {
|
||
|
throw new IOException(C14957gcv.c("TYPE_GOAWAY unexpected error code: ", Integer.valueOf(n2)));
|
||
|
}
|
||
|
C15155gij c15155gij = C15155gij.e;
|
||
|
if (i4 > 0) {
|
||
|
c15155gij = this.source.c(i4);
|
||
|
}
|
||
|
handler.goAway(n, fromHttp2, c15155gij);
|
||
|
}
|
||
|
|
||
|
private final void readWindowUpdate(Handler handler, int i, int i2, int i3) throws IOException {
|
||
|
if (i != 4) {
|
||
|
throw new IOException(C14957gcv.c("TYPE_WINDOW_UPDATE length !=4: ", Integer.valueOf(i)));
|
||
|
}
|
||
|
long and = Util.and(this.source.n(), 2147483647L);
|
||
|
if (and == 0) {
|
||
|
throw new IOException("windowSizeIncrement was 0");
|
||
|
}
|
||
|
handler.windowUpdate(i3, and);
|
||
|
}
|
||
|
|
||
|
@Override // java.io.Closeable, java.lang.AutoCloseable
|
||
|
public final void close() throws IOException {
|
||
|
this.source.close();
|
||
|
}
|
||
|
|
||
|
/* loaded from: classes.dex */
|
||
|
public static final class ContinuationSource implements giD {
|
||
|
private int flags;
|
||
|
private int left;
|
||
|
private int length;
|
||
|
private int padding;
|
||
|
private final InterfaceC15149gid source;
|
||
|
private int streamId;
|
||
|
|
||
|
@Override // o.giD, java.io.Closeable, java.lang.AutoCloseable
|
||
|
public final void close() throws IOException {
|
||
|
}
|
||
|
|
||
|
public ContinuationSource(InterfaceC15149gid interfaceC15149gid) {
|
||
|
C14957gcv.e(interfaceC15149gid, "");
|
||
|
this.source = interfaceC15149gid;
|
||
|
}
|
||
|
|
||
|
@Override // o.giD
|
||
|
public final long read(C15111ghZ c15111ghZ, long j) throws IOException {
|
||
|
C14957gcv.e(c15111ghZ, "");
|
||
|
while (true) {
|
||
|
int i = this.left;
|
||
|
if (i == 0) {
|
||
|
this.source.j(this.padding);
|
||
|
this.padding = 0;
|
||
|
if ((this.flags & 4) != 0) {
|
||
|
return -1L;
|
||
|
}
|
||
|
readContinuationHeader();
|
||
|
} else {
|
||
|
long read = this.source.read(c15111ghZ, Math.min(j, i));
|
||
|
if (read == -1) {
|
||
|
return -1L;
|
||
|
}
|
||
|
this.left -= (int) read;
|
||
|
return read;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // o.giD
|
||
|
public final C15139giB timeout() {
|
||
|
return this.source.timeout();
|
||
|
}
|
||
|
|
||
|
private final void readContinuationHeader() throws IOException {
|
||
|
int i = this.streamId;
|
||
|
int readMedium = Util.readMedium(this.source);
|
||
|
this.left = readMedium;
|
||
|
this.length = readMedium;
|
||
|
int and = Util.and(this.source.f(), 255);
|
||
|
this.flags = Util.and(this.source.f(), 255);
|
||
|
if (Http2Reader.Companion.getLogger().isLoggable(Level.FINE)) {
|
||
|
Http2Reader.Companion.getLogger().fine(Http2.INSTANCE.frameLog(true, this.streamId, this.length, and, this.flags));
|
||
|
}
|
||
|
int n = this.source.n() & Integer.MAX_VALUE;
|
||
|
this.streamId = n;
|
||
|
if (and == 9) {
|
||
|
if (n != i) {
|
||
|
throw new IOException("TYPE_CONTINUATION streamId changed");
|
||
|
}
|
||
|
} else {
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
sb.append(and);
|
||
|
sb.append(" != TYPE_CONTINUATION");
|
||
|
throw new IOException(sb.toString());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public final void setStreamId(int i) {
|
||
|
this.streamId = i;
|
||
|
}
|
||
|
|
||
|
public final void setPadding(int i) {
|
||
|
this.padding = i;
|
||
|
}
|
||
|
|
||
|
public final void setLength(int i) {
|
||
|
this.length = i;
|
||
|
}
|
||
|
|
||
|
public final void setLeft(int i) {
|
||
|
this.left = i;
|
||
|
}
|
||
|
|
||
|
public final void setFlags(int i) {
|
||
|
this.flags = i;
|
||
|
}
|
||
|
|
||
|
public final int getStreamId() {
|
||
|
return this.streamId;
|
||
|
}
|
||
|
|
||
|
public final int getPadding() {
|
||
|
return this.padding;
|
||
|
}
|
||
|
|
||
|
public final int getLength() {
|
||
|
return this.length;
|
||
|
}
|
||
|
|
||
|
public final int getLeft() {
|
||
|
return this.left;
|
||
|
}
|
||
|
|
||
|
public final int getFlags() {
|
||
|
return this.flags;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* loaded from: classes.dex */
|
||
|
public static final class Companion {
|
||
|
private Companion() {
|
||
|
}
|
||
|
|
||
|
public final Logger getLogger() {
|
||
|
return Http2Reader.logger;
|
||
|
}
|
||
|
|
||
|
public final int lengthWithoutPadding(int i, int i2, int i3) throws IOException {
|
||
|
if ((i2 & 8) != 0) {
|
||
|
i--;
|
||
|
}
|
||
|
if (i3 <= i) {
|
||
|
return i - i3;
|
||
|
}
|
||
|
StringBuilder sb = new StringBuilder("PROTOCOL_ERROR padding ");
|
||
|
sb.append(i3);
|
||
|
sb.append(" > remaining length ");
|
||
|
sb.append(i);
|
||
|
throw new IOException(sb.toString());
|
||
|
}
|
||
|
|
||
|
public /* synthetic */ Companion(C14953gcr c14953gcr) {
|
||
|
this();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static {
|
||
|
Logger logger2 = Logger.getLogger(Http2.class.getName());
|
||
|
C14957gcv.c(logger2, "");
|
||
|
logger = logger2;
|
||
|
}
|
||
|
}
|