--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.drda.DDMReader\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.drda;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.ByteArrayInputStream;\r
+import java.math.BigDecimal;\r
+\r
+/**\r
+ The DDMReader is used to read DRDA protocol. DRDA Protocol is divided into\r
+ three layers corresponding to the DDM three-tier architecture. For each layer,\r
+ their is a DSS (Data Stream Structure) defined.\r
+ Layer A Communications management services\r
+ Layer B Agent services\r
+ Layer C Data management services\r
+ <P>\r
+ At layer A are request, reply and data correlation, structure chaining,\r
+ continuation or termination of chains when errors are detected, interleaving\r
+ and multi-leaving request, reply, and data DSSs for multitasking environments.\r
+ For TCP/IP, the format of the DDM envelope is\r
+ 2 bytes Length of the data\r
+ 1 byte 'D0' - indicates DDM data\r
+ 1 byte DDM format byte(DSSFMT) - type of DSS(RQSDSS,RPYDSS), whether it is\r
+ chained, information about the next chained DSS\r
+ 2 bytes request correlation identifier\r
+ <P>\r
+ The correlation identifier ties together a request, the request data and the\r
+ reply. In a chained DSS, each request has a correlation identifier which\r
+ is higher than the previous request (all correlation identifiers must\r
+ be greater than 0).\r
+ <P>\r
+ At layer B are object mapping, object validation and command routing.\r
+ Layer B objects with data 5 bytes less than 32K bytes consist of\r
+ 2 bytes Length\r
+ 2 bytes Type of the object (code point)\r
+ Object data\r
+ Object data is either SCALAR or COLLECTION data. Scalar data consists of\r
+ a string of bytes formatted as the class description of the object required.\r
+ Collections consist of a set of objects in which the entries in the collection\r
+ are nested within the length/ code point of the collection.\r
+ <P>\r
+ Layer B objects with data >=32763 bytes long format is \r
+ 2 bytes Length - length of class, length, and extended total length fields\r
+ (high order bit set, indicating >=32763)\r
+ 2 bytes Type of the object (code point)\r
+ n bytes Extended total length - length of the object\r
+ (n = Length - 4)\r
+ Object data\r
+ <P>\r
+ At layer C are services each class of DDM object provides.\r
+\r
+ |-------------------------------------------|\r
+ Layer C | Specific | Specific | Specific |\r
+ | Commands | Replies | Scalars and |\r
+ | and their | and their | Collections |\r
+ |-------------------------------------------|----------------|\r
+ Layer B | Commands | Reply | Scalars and | Communications |\r
+ | | Messages | Collections | |\r
+ |-----------|---------------|---------------|----------------|\r
+ Layer A | RQSDSS | RPYDSS | OBJDSS | CMNDSS |\r
+ | | | | Mapped Data |\r
+ |-----------|---------------|---------------|----------------|\r
+ | DDM Data Stream Structures |\r
+ |------------------------------------------------------------|\r
+ \r
+ DSS's may be chained so that more than one can be transmitted at a time\r
+ to improve performance.\r
+ For more details, see DRDA Volume 3 (Distributed Data Management(DDM)\r
+ Architecture (DDS definition)\r
+*/\r
+class DDMReader\r
+{\r
+ private final static int DEFAULT_BUFFER_SIZE = 32767;\r
+ private final static int MAX_MARKS_NESTING = 10;\r
+ private final static int NO_CODEPOINT = -1;\r
+ private final static int EMPTY_STACK = -1;\r
+ private final static boolean ADJUST_LENGTHS = true;\r
+ private final static boolean NO_ADJUST_LENGTHS = false;\r
+ private final static long MAX_EXTDTA_SIZE= Long.MAX_VALUE;\r
+ private static boolean internalTrace = true;\r
+ \r
+\r
+ // magnitude represented in an int array, used in BigDecimal conversion\r
+ private static final int[][] tenRadixMagnitude = {\r
+ { 0x3b9aca00 }, // 10^9\r
+ { 0x0de0b6b3, 0xa7640000 }, // 10^18\r
+ { 0x033b2e3c, 0x9fd0803c, 0xe8000000 }, // 10^27\r
+ };\r
+\r
+ private DRDAConnThread agent;\r
+ private CcsidManager ccsidManager;\r
+\r
+ // data buffer\r
+ private byte[] buffer;\r
+ private int pos;\r
+ private int count;\r
+\r
+ // DDM object collection\r
+ // top of stack\r
+ private int topDdmCollectionStack;\r
+ // length of each object in the stack\r
+ private long[] ddmCollectionLenStack;\r
+\r
+ // DDM object length\r
+ private long ddmScalarLen;\r
+\r
+ // DSS Length\r
+ private int dssLength;\r
+\r
+ // DSS is larger than 32762 (continuation bit is set) so DSS is continued\r
+ private boolean dssIsContinued;\r
+\r
+ private boolean terminateChainOnErr;\r
+\r
+ // next DSS in the chain has the same correlator\r
+ private boolean dssIsChainedWithSameID;\r
+\r
+ // next DSS in the chain has a different correlator\r
+ private boolean dssIsChainedWithDiffID;\r
+ \r
+ // correlation id for the current DSS\r
+ private int dssCorrelationID;\r
+\r
+ // previous corelation id\r
+ private int prevCorrelationID;\r
+\r
+ // current server codepoint\r
+ private int svrcod;\r
+\r
+ // trace object of the associated session\r
+ private DssTrace dssTrace;\r
+\r
+ // input stream\r
+ private InputStream inputStream;\r
+ \r
+ // State whether doing layer B Streaming or not.\r
+ private boolean doingLayerBStreaming = false;;\r
+\r
+ // constructor\r
+ DDMReader (DRDAConnThread agent, DssTrace dssTrace)\r
+ {\r
+ buffer = new byte[DEFAULT_BUFFER_SIZE];\r
+ ddmCollectionLenStack = new long[MAX_MARKS_NESTING];\r
+ initialize(agent, dssTrace);\r
+ }\r
+ /**\r
+ * This constructor is used for testing the protocol\r
+ * It is used by TestProto to read the protocol returned by the\r
+ * server \r
+ */\r
+ DDMReader(CcsidManager ccsidManager, InputStream inputStream)\r
+ {\r
+ buffer = new byte[DEFAULT_BUFFER_SIZE];\r
+ ddmCollectionLenStack = new long[MAX_MARKS_NESTING];\r
+ this.ccsidManager = ccsidManager;\r
+ this.inputStream = inputStream;\r
+ initialize(null, null);\r
+ // turn off tracing\r
+ internalTrace = false;\r
+ }\r
+ /**\r
+ * This initializer is used for testing the protocol\r
+ * It is used by TestProto for the reader it uses\r
+ */\r
+ protected void initialize(InputStream inputStream)\r
+ {\r
+ this.inputStream = inputStream;\r
+ initialize(null, null);\r
+ }\r
+\r
+ /**\r
+ * Initialize values for this session, the reader is reused so we need to\r
+ * set null and 0 values\r
+ */\r
+ protected void initialize(DRDAConnThread agent, DssTrace dssTrace)\r
+ {\r
+ this.agent = agent;\r
+ if (agent != null)\r
+ {\r
+ ccsidManager = agent.ccsidManager;\r
+ inputStream = agent.getInputStream();\r
+ }\r
+ topDdmCollectionStack = EMPTY_STACK;\r
+ svrcod = 0;\r
+ pos = 0;\r
+ count = 0;\r
+ ddmScalarLen = 0;\r
+ dssLength = 0;\r
+ prevCorrelationID = DssConstants.CORRELATION_ID_UNKNOWN;\r
+ dssCorrelationID = DssConstants.CORRELATION_ID_UNKNOWN;\r
+ this.dssTrace = dssTrace;\r
+ }\r
+\r
+ protected boolean terminateChainOnErr()\r
+ {\r
+ return terminateChainOnErr;\r
+ }\r
+\r
+ /**\r
+ * Next DSS has same correlator as current DSS\r
+ *\r
+ * @return true if next DSS has the same correlator as current DSS\r
+ */\r
+ protected boolean isChainedWithSameID()\r
+ {\r
+ return dssIsChainedWithSameID;\r
+ }\r
+\r
+ /**\r
+ * Next DSS has different correlator than current DSS\r
+ *\r
+ * @return true if next DSS has a different correlator than current DSS\r
+ */\r
+ protected boolean isChainedWithDiffID()\r
+ {\r
+ return dssIsChainedWithDiffID;\r
+ }\r
+\r
+ /**\r
+ * Length of current DDM object\r
+ *\r
+ * @return length of DDM object\r
+ */\r
+ protected long getDdmLength()\r
+ {\r
+ return ddmScalarLen;\r
+ }\r
+\r
+ /**\r
+ * Is there more in this DDM object\r
+ *\r
+ * @return true if DDM length is > 0\r
+ */\r
+ protected boolean moreDdmData()\r
+ {\r
+ return ddmScalarLen > 0;\r
+ }\r
+\r
+ /**\r
+ * Is there more in this DDS object\r
+ *\r
+ * @return true if DDS length is > 0\r
+ */\r
+ protected boolean moreDssData()\r
+ {\r
+ return dssLength > 0;\r
+ }\r
+\r
+ /** \r
+ * Is there more data in the buffer\r
+ *\r
+ * @return true if there is more data in the buffer\r
+ */\r
+ protected boolean moreData()\r
+ {\r
+ return (pos - count) > 0;\r
+ }\r
+\r
+ /**\r
+ * Check for the command protocol\r
+ *\r
+ * @return true if this is a command; false otherwise\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected boolean isCmd() throws DRDAProtocolException, java.io.UnsupportedEncodingException\r
+ {\r
+ ensureALayerDataInBuffer(4);\r
+ String val = new String(buffer, 0, 4, NetworkServerControlImpl.DEFAULT_ENCODING);\r
+ return NetworkServerControlImpl.isCmd(val);\r
+ }\r
+\r
+ /**\r
+ * Read DSS header\r
+ * DSS Header format is \r
+ * 2 bytes - length\r
+ * 1 byte - 'D0' - indicates DDM data\r
+ * 1 byte - DSS format \r
+ * |---|---------|----------|\r
+ * | 0 | flags | type |\r
+ * |---|---------|----------|\r
+ * | 0 | 1 2 3 | 4 5 6 7 |\r
+ * |---|---------|----------|\r
+ * bit 0 - '0'\r
+ * bit 1 - '0' - unchained, '1' - chained\r
+ * bit 2 - '0' - do not continue on error, '1' - continue on error\r
+ * bit 3 - '0' - next DSS has different correlator, '1' - next DSS has\r
+ * same correlator\r
+ * type - 1 - Request DSS\r
+ * - 2 - Reply DSS\r
+ * - 3 - Object DSS\r
+ * - 4 - Communications DSS\r
+ * - 5 - Request DSS where no reply is expected\r
+ * 2 bytes - request correlation id\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int readDssHeader () throws DRDAProtocolException\r
+ {\r
+ ensureALayerDataInBuffer (6);\r
+\r
+ // read out the DSS length\r
+ dssLength = ((buffer[pos] & 0xff) << 8) +\r
+ ((buffer[pos + 1] & 0xff) << 0);\r
+ pos += 2;\r
+ // check for the continuation bit and update length as needed.\r
+ if ((dssLength & DssConstants.CONTINUATION_BIT) == \r
+ DssConstants.CONTINUATION_BIT) \r
+ {\r
+ dssLength = DssConstants.MAX_DSS_LENGTH;\r
+ dssIsContinued = true;\r
+ }\r
+ else \r
+ {\r
+ dssIsContinued = false;\r
+ }\r
+\r
+ if (dssLength < 6)\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_DSS_LESS_THAN_6,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+\r
+ // If the GDS id is not valid, or\r
+ // if the reply is not an RQSDSS nor\r
+ // a OBJDSS, then throw an exception.\r
+\r
+ if ((buffer[pos++] & 0xff) != DssConstants.DSS_ID)\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_CBYTE_NOT_D0,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+\r
+ int gdsFormatter = buffer[pos++] & 0xff;\r
+ \r
+ if (((gdsFormatter & 0x0F) != DssConstants.DSSFMT_RQSDSS)\r
+ &&((gdsFormatter & 0x0F) != DssConstants.DSSFMT_OBJDSS)) \r
+ {\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_FBYTE_NOT_SUPPORTED,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+\r
+ // Determine if the current DSS is chained with the\r
+ // next DSS, with the same or different request ID.\r
+ if ((gdsFormatter & DssConstants.DSSCHAIN) == DssConstants.DSSCHAIN) \r
+ { // on indicates structure chained to next structure\r
+ if ((gdsFormatter & DssConstants.DSSCHAIN_SAME_ID) \r
+ == DssConstants.DSSCHAIN_SAME_ID) \r
+ {\r
+ dssIsChainedWithSameID = true;\r
+ dssIsChainedWithDiffID = false;\r
+ }\r
+ else \r
+ {\r
+ dssIsChainedWithSameID = false;\r
+ dssIsChainedWithDiffID = true;\r
+ }\r
+ if ((gdsFormatter & DssConstants.DSSCHAIN_ERROR_CONTINUE) \r
+ == DssConstants.DSSCHAIN_ERROR_CONTINUE)\r
+ terminateChainOnErr = false;\r
+ else\r
+ terminateChainOnErr = true;\r
+ }\r
+ else \r
+ {\r
+ // chaining bit not b'1', make sure DSSFMT same id not b'1'\r
+ if ((gdsFormatter & DssConstants.DSSCHAIN_SAME_ID) \r
+ == DssConstants.DSSCHAIN_SAME_ID) \r
+ { // Next DSS can not have same correlator\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_CHAIN_OFF_SAME_NEXT_CORRELATOR,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+ // chaining bit not b'1', make sure no error continuation\r
+ if ((gdsFormatter & DssConstants.DSSCHAIN_ERROR_CONTINUE) \r
+ == DssConstants.DSSCHAIN_ERROR_CONTINUE) \r
+ { // must be 'do not continue on error'\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_CHAIN_OFF_ERROR_CONTINUE,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+\r
+ dssIsChainedWithSameID = false;\r
+ dssIsChainedWithDiffID = false;\r
+ }\r
+\r
+ dssCorrelationID =\r
+ ((buffer[pos] & 0xff) << 8) +\r
+ ((buffer[pos + 1] & 0xff) << 0);\r
+ pos += 2;\r
+ if (SanityManager.DEBUG)\r
+ trace("dssLength = " + dssLength + " correlationID = " + dssCorrelationID);\r
+\r
+ //check that correlationID is the same as previous\r
+ if (prevCorrelationID != DssConstants.CORRELATION_ID_UNKNOWN && \r
+ dssCorrelationID != prevCorrelationID)\r
+ {\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_CHAIN_OFF_ERROR_CONTINUE,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+ \r
+ // set up previous correlation id to check that next DSS is correctly\r
+ // formatted\r
+ if (dssIsChainedWithSameID)\r
+ prevCorrelationID = dssCorrelationID;\r
+ else\r
+ prevCorrelationID = DssConstants.CORRELATION_ID_UNKNOWN;\r
+\r
+ dssLength -= 6;\r
+\r
+ return dssCorrelationID;\r
+ }\r
+ /**\r
+ * Read Reply DSS\r
+ * This is used in testing the protocol. We shouldn't see a reply\r
+ * DSS when we are servicing DRDA commands\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected void readReplyDss() throws DRDAProtocolException\r
+ {\r
+ ensureALayerDataInBuffer (6);\r
+\r
+ // read out the DSS length\r
+ dssLength = ((buffer[pos++] & 0xff) << 8) +\r
+ ((buffer[pos++] & 0xff) << 0);\r
+\r
+ // check for the continuation bit and update length as needed.\r
+ if ((dssLength & DssConstants.CONTINUATION_BIT) == \r
+ DssConstants.CONTINUATION_BIT) \r
+ {\r
+ dssLength = DssConstants.MAX_DSS_LENGTH;\r
+ dssIsContinued = true;\r
+ }\r
+ else \r
+ {\r
+ dssIsContinued = false;\r
+ }\r
+\r
+ if (dssLength < 6)\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_DSS_LESS_THAN_6,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+\r
+ // If the GDS id is not valid, throw exception\r
+\r
+ if ((buffer[pos++] & 0xff) != DssConstants.DSS_ID)\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_CBYTE_NOT_D0,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+\r
+ int gdsFormatter = buffer[pos++] & 0xff;\r
+ \r
+ // Determine if the current DSS is chained with the\r
+ // next DSS, with the same or different request ID.\r
+ if ((gdsFormatter & DssConstants.DSSCHAIN) == DssConstants.DSSCHAIN) \r
+ { // on indicates structure chained to next structure\r
+ if ((gdsFormatter & DssConstants.DSSCHAIN_SAME_ID) \r
+ == DssConstants.DSSCHAIN_SAME_ID) \r
+ {\r
+ dssIsChainedWithSameID = true;\r
+ dssIsChainedWithDiffID = false;\r
+ }\r
+ else \r
+ {\r
+ dssIsChainedWithSameID = false;\r
+ dssIsChainedWithDiffID = true;\r
+ }\r
+ }\r
+ else \r
+ {\r
+ dssIsChainedWithSameID = false;\r
+ dssIsChainedWithDiffID = false;\r
+ }\r
+\r
+ dssCorrelationID =\r
+ ((buffer[pos++] & 0xff) << 8) +\r
+ ((buffer[pos++] & 0xff) << 0);\r
+\r
+ if (SanityManager.DEBUG) \r
+ trace("dssLength = " + dssLength + " correlationID = " + dssCorrelationID);\r
+\r
+ dssLength -= 6;\r
+\r
+ }\r
+\r
+ /**\r
+ * Read the DDM Length and CodePoint\r
+ *\r
+ * @param isLayerBStreamingPossible true only when layer B streaming is possible\r
+ * @return - returns codepoint\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int readLengthAndCodePoint( boolean isLayerBStreamingPossible ) \r
+ throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (4, NO_ADJUST_LENGTHS);\r
+\r
+ ddmScalarLen = readCodePoint();\r
+ int codePoint = readCodePoint();\r
+ \r
+ if (SanityManager.DEBUG)\r
+ trace("length = "+ ddmScalarLen + " codepoint = " + java.lang.Integer.toHexString(codePoint));\r
+ // SYNERRCD 0x0D - Object code point index not supported.\r
+ // the object codepoint index will not be checked here since\r
+ // the parse methods will catch any incorrect/unexpected codepoint values\r
+ // and report them as unsupported objects or parameters.\r
+\r
+ // Check if this DDM has extended length field\r
+ if ((ddmScalarLen & DssConstants.CONTINUATION_BIT) == DssConstants.CONTINUATION_BIT) \r
+ {\r
+ int numberOfExtendedLenBytes = ((int)ddmScalarLen - \r
+ DssConstants.CONTINUATION_BIT) - 4;\r
+ int adjustSize = 0;\r
+ ensureBLayerDataInBuffer (numberOfExtendedLenBytes, NO_ADJUST_LENGTHS);\r
+ switch (numberOfExtendedLenBytes) {\r
+ case 8:\r
+ ddmScalarLen =\r
+ ((buffer[pos++] & 0xFFL) << 56) +\r
+ ((buffer[pos++] & 0xFFL) << 48) +\r
+ ((buffer[pos++] & 0xFFL) << 40) +\r
+ ((buffer[pos++] & 0xFFL) << 32) +\r
+ ((buffer[pos++] & 0xFFL) << 24) +\r
+ ((buffer[pos++] & 0xFFL) << 16) +\r
+ ((buffer[pos++] & 0xFFL) << 8) +\r
+ ((buffer[pos++] & 0xFFL) << 0);\r
+ adjustSize = 12;\r
+ break;\r
+ case 6:\r
+ ddmScalarLen =\r
+ ((buffer[pos++] & 0xFFL) << 40) +\r
+ ((buffer[pos++] & 0xFFL) << 32) +\r
+ ((buffer[pos++] & 0xFFL) << 24) +\r
+ ((buffer[pos++] & 0xFFL) << 16) +\r
+ ((buffer[pos++] & 0xFFL) << 8) +\r
+ ((buffer[pos++] & 0xFFL) << 0);\r
+ adjustSize = 10;\r
+ break;\r
+ case 4:\r
+ ddmScalarLen =\r
+ ((buffer[pos++] & 0xFFL) << 24) +\r
+ ((buffer[pos++] & 0xFFL) << 16) +\r
+ ((buffer[pos++] & 0xFFL) << 8) +\r
+ ((buffer[pos++] & 0xFFL) << 0);\r
+ adjustSize = 8;\r
+ break;\r
+ \r
+ case 0:\r
+ \r
+ if( isLayerBStreamingPossible &&\r
+ ( codePoint == CodePoint.EXTDTA || \r
+ codePoint == CodePoint.QRYDTA ) ){\r
+ \r
+ startLayerBStreaming();\r
+ adjustSize = 4;\r
+ \r
+ }else {\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_INCORRECT_EXTENDED_LEN,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+ \r
+ break;\r
+ \r
+ default:\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_INCORRECT_EXTENDED_LEN,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+\r
+ // adjust the lengths here. this is a special case since the\r
+ // extended length bytes do not include their own length.\r
+ for (int i = 0; i <= topDdmCollectionStack; i++) {\r
+ ddmCollectionLenStack[i] -= adjustSize;\r
+ }\r
+ dssLength -= adjustSize;\r
+ }\r
+ else {\r
+ if (ddmScalarLen < 4)\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_OBJ_LEN_LESS_THAN_4,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ adjustLengths (4);\r
+ }\r
+ return codePoint;\r
+ }\r
+\r
+ /**\r
+ * Read the CodePoint\r
+ *\r
+ * @return - returns codepoint\r
+ */\r
+ protected int readCodePoint()\r
+ {\r
+ return( ((buffer[pos++] & 0xff) << 8) +\r
+ ((buffer[pos++] & 0xff) << 0));\r
+ }\r
+\r
+ /**\r
+ * Push DDM Length on to collection stack\r
+ */\r
+ protected void markCollection()\r
+ {\r
+ ddmCollectionLenStack[++topDdmCollectionStack] = ddmScalarLen;\r
+ ddmScalarLen = 0;\r
+ }\r
+\r
+ /**\r
+ * Get the next CodePoint from a collection\r
+ * @return NO_CODEPOINT if collection stack is empty or remaining length is\r
+ * 0; otherwise, read length and code point\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int getCodePoint() throws DRDAProtocolException\r
+ {\r
+ if (topDdmCollectionStack == EMPTY_STACK) \r
+ {\r
+ return NO_CODEPOINT;\r
+ }\r
+ else \r
+ {\r
+ // if the collecion is exhausted then return NO_CODEPOINT\r
+ if (ddmCollectionLenStack[topDdmCollectionStack] == 0) \r
+ {\r
+ // done with this collection so remove it's length from the stack\r
+ ddmCollectionLenStack[topDdmCollectionStack--] = 0;\r
+ return NO_CODEPOINT;\r
+ }\r
+ else {\r
+ return readLengthAndCodePoint( false );\r
+ }\r
+ }\r
+ }\r
+ /**\r
+ * Get the next CodePoint from a collection and check that it matches the specified\r
+ * CodePoint\r
+ * @param codePointCheck - codePoint to check against\r
+ * @return codePoint\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int getCodePoint(int codePointCheck) throws DRDAProtocolException\r
+ {\r
+ int codePoint = getCodePoint();\r
+ if (codePoint != codePointCheck)\r
+ agent.missingCodePoint(codePoint);\r
+ return codePoint;\r
+ }\r
+ /**\r
+ * The following routines read different types from the input stream\r
+ * Data can be in network order or platform order depending on whether the\r
+ * data is part of the protocol or data being received\r
+ * The platform is determined by EXCSAT protocol\r
+ */\r
+\r
+ /**\r
+ * Read byte value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected byte readByte () throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (1, ADJUST_LENGTHS);\r
+ return buffer[pos++];\r
+ }\r
+\r
+ /**\r
+ * Read byte value and mask out high order bytes before returning\r
+ * @return value\r
+ */\r
+ protected int readUnsignedByte () throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (1, ADJUST_LENGTHS);\r
+ return (int ) (buffer[pos++] & 0xff);\r
+ }\r
+\r
+ /**\r
+ * Read network short value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int readNetworkShort () throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (2, ADJUST_LENGTHS);\r
+ return ((buffer[pos++] & 0xff) << 8) +\r
+ ((buffer[pos++] & 0xff) << 0);\r
+ }\r
+\r
+ /**\r
+ * Read signed network short value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int readSignedNetworkShort () throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (2, ADJUST_LENGTHS);\r
+ return (short)(((buffer[pos++] & 0xff) << 8) +\r
+ ((buffer[pos++] & 0xff) << 0));\r
+ }\r
+ /**\r
+ * Read platform short value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected short readShort (int byteOrder) throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (2, ADJUST_LENGTHS);\r
+ short s = SignedBinary.getShort (buffer, pos, byteOrder);\r
+\r
+ pos += 2;\r
+\r
+ return s;\r
+ }\r
+\r
+ /**\r
+ * Read network int value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int readNetworkInt () throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (4, ADJUST_LENGTHS);\r
+ return ((buffer[pos++] & 0xff) << 24) +\r
+ ((buffer[pos++] & 0xff) << 16) +\r
+ ((buffer[pos++] & 0xff) << 8) +\r
+ ((buffer[pos++] & 0xff) << 0);\r
+ }\r
+\r
+ /**\r
+ * Read platform int value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected int readInt (int byteOrder) throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (4, ADJUST_LENGTHS);\r
+ int i = SignedBinary.getInt (buffer, pos, byteOrder);\r
+\r
+ pos += 4;\r
+\r
+ return i;\r
+ }\r
+\r
+ /**\r
+ * Read network long value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected long readNetworkLong () throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (8, ADJUST_LENGTHS);\r
+\r
+ return ((buffer[pos++] & 0xffL) << 56) +\r
+ ((buffer[pos++] & 0xffL) << 48) +\r
+ ((buffer[pos++] & 0xffL) << 40) +\r
+ ((buffer[pos++] & 0xffL) << 32) +\r
+ ((buffer[pos++] & 0xffL) << 24) +\r
+ ((buffer[pos++] & 0xffL) << 16) +\r
+ ((buffer[pos++] & 0xffL) << 8) +\r
+ ((buffer[pos++] & 0xffL) << 0);\r
+ }\r
+\r
+ \r
+ /**\r
+ * Read network six byte value and put it in a long v\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected long readNetworkSixByteLong() throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (6, ADJUST_LENGTHS);\r
+\r
+ return (\r
+ ((buffer[pos++] & 0xffL) << 40) +\r
+ ((buffer[pos++] & 0xffL) << 32) +\r
+ ((buffer[pos++] & 0xffL) << 24) +\r
+ ((buffer[pos++] & 0xffL) << 16) +\r
+ ((buffer[pos++] & 0xffL) << 8) +\r
+ ((buffer[pos++] & 0xffL) << 0));\r
+ }\r
+\r
+ /**\r
+ * Read platform long value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected long readLong (int byteOrder) throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (8, ADJUST_LENGTHS);\r
+ long l = SignedBinary.getLong (buffer, pos, byteOrder);\r
+\r
+ pos += 8;\r
+\r
+ return l;\r
+ }\r
+\r
+ /**\r
+ * Read platform float value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected float readFloat(int byteOrder) throws DRDAProtocolException\r
+ {\r
+ return Float.intBitsToFloat(readInt(byteOrder));\r
+ }\r
+\r
+ /**\r
+ * Read platform double value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected double readDouble(int byteOrder) throws DRDAProtocolException\r
+ {\r
+ return Double.longBitsToDouble(readLong(byteOrder));\r
+ }\r
+\r
+ /**\r
+ * Read a BigDecimal value\r
+ * @param precision of the BigDecimal\r
+ * @param scale of the BigDecimal\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected BigDecimal readBigDecimal(int precision, int scale) throws DRDAProtocolException\r
+ {\r
+ // The byte-length of a packed decimal with precision p is always p/2 + 1\r
+ int length = precision / 2 + 1;\r
+\r
+ ensureBLayerDataInBuffer (length, ADJUST_LENGTHS);\r
+\r
+ // check for sign.\r
+ int signum;\r
+ if ((buffer[pos+length-1] & 0x0F) == 0x0D)\r
+ signum = -1;\r
+ else\r
+ signum = 1;\r
+\r
+ if (precision <= 9) {\r
+ // can be handled by int without overflow.\r
+ int value = packedNybblesToInt(buffer, pos, 0, length*2-1);\r
+\r
+ // convert value to a byte array of magnitude.\r
+ byte[] magnitude = new byte[4];\r
+ magnitude[0] = (byte)(value >>> 24);\r
+ magnitude[1] = (byte)(value >>> 16);\r
+ magnitude[2] = (byte)(value >>> 8);\r
+ magnitude[3] = (byte)(value);\r
+\r
+ pos += length;\r
+ return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale);\r
+ }\r
+ else if (precision <= 18) {\r
+ // can be handled by long without overflow.\r
+ long value = packedNybblesToLong(buffer, pos, 0, length*2-1);\r
+\r
+ // convert value to a byte array of magnitude.\r
+ byte[] magnitude = new byte[8];\r
+ magnitude[0] = (byte)(value >>> 56);\r
+ magnitude[1] = (byte)(value >>> 48);\r
+ magnitude[2] = (byte)(value >>> 40);\r
+ magnitude[3] = (byte)(value >>> 32);\r
+ magnitude[4] = (byte)(value >>> 24);\r
+ magnitude[5] = (byte)(value >>> 16);\r
+ magnitude[6] = (byte)(value >>> 8);\r
+ magnitude[7] = (byte)(value);\r
+\r
+ pos += length;\r
+ return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale);\r
+ }\r
+ else if (precision <= 27) {\r
+ // get the value of last 9 digits (5 bytes).\r
+ int lo = packedNybblesToInt(buffer, pos, (length-5)*2, 9);\r
+ // get the value of another 9 digits (5 bytes).\r
+ int me = packedNybblesToInt(buffer, pos, (length-10)*2+1, 9);\r
+ // get the value of the rest digits.\r
+ int hi = packedNybblesToInt(buffer, pos, 0, (length-10)*2+1);\r
+\r
+ // compute the int array of magnitude.\r
+ int[] value = computeMagnitude(new int[] {hi, me, lo});\r
+\r
+ // convert value to a byte array of magnitude.\r
+ byte[] magnitude = new byte[12];\r
+ magnitude[0] = (byte)(value[0] >>> 24);\r
+ magnitude[1] = (byte)(value[0] >>> 16);\r
+ magnitude[2] = (byte)(value[0] >>> 8);\r
+ magnitude[3] = (byte)(value[0]);\r
+ magnitude[4] = (byte)(value[1] >>> 24);\r
+ magnitude[5] = (byte)(value[1] >>> 16);\r
+ magnitude[6] = (byte)(value[1] >>> 8);\r
+ magnitude[7] = (byte)(value[1]);\r
+ magnitude[8] = (byte)(value[2] >>> 24);\r
+ magnitude[9] = (byte)(value[2] >>> 16);\r
+ magnitude[10] = (byte)(value[2] >>> 8);\r
+ magnitude[11] = (byte)(value[2]);\r
+\r
+ pos += length;\r
+ return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale);\r
+ }\r
+ else if (precision <= 31) {\r
+ // get the value of last 9 digits (5 bytes).\r
+ int lo = packedNybblesToInt(buffer, pos, (length-5)*2, 9);\r
+ // get the value of another 9 digits (5 bytes).\r
+ int meLo = packedNybblesToInt(buffer, pos, (length-10)*2+1, 9);\r
+ // get the value of another 9 digits (5 bytes).\r
+ int meHi = packedNybblesToInt(buffer, pos, (length-14)*2, 9);\r
+ // get the value of the rest digits.\r
+ int hi = packedNybblesToInt(buffer, pos, 0, (length-14)*2);\r
+\r
+ // compute the int array of magnitude.\r
+ int[] value = computeMagnitude(new int[] {hi, meHi, meLo, lo});\r
+\r
+ // convert value to a byte array of magnitude.\r
+ byte[] magnitude = new byte[16];\r
+ magnitude[0] = (byte)(value[0] >>> 24);\r
+ magnitude[1] = (byte)(value[0] >>> 16);\r
+ magnitude[2] = (byte)(value[0] >>> 8);\r
+ magnitude[3] = (byte)(value[0]);\r
+ magnitude[4] = (byte)(value[1] >>> 24);\r
+ magnitude[5] = (byte)(value[1] >>> 16);\r
+ magnitude[6] = (byte)(value[1] >>> 8);\r
+ magnitude[7] = (byte)(value[1]);\r
+ magnitude[8] = (byte)(value[2] >>> 24);\r
+ magnitude[9] = (byte)(value[2] >>> 16);\r
+ magnitude[10] = (byte)(value[2] >>> 8);\r
+ magnitude[11] = (byte)(value[2]);\r
+ magnitude[12] = (byte)(value[3] >>> 24);\r
+ magnitude[13] = (byte)(value[3] >>> 16);\r
+ magnitude[14] = (byte)(value[3] >>> 8);\r
+ magnitude[15] = (byte)(value[3]);\r
+\r
+ pos += length;\r
+ return new java.math.BigDecimal (new java.math.BigInteger(signum, magnitude), scale);\r
+ }\r
+ else {\r
+ pos += length;\r
+ // throw an exception here if nibbles is greater than 31\r
+ throw new java.lang.IllegalArgumentException("Decimal may only be up to 31 digits!");\r
+ }\r
+ }\r
+\r
+ \r
+\r
+ byte[] getExtData (boolean checkNullability) throws DRDAProtocolException\r
+ {\r
+ return getExtData(ddmScalarLen, checkNullability);\r
+ }\r
+\r
+ \r
+ /**\r
+ * Creates an InputStream which can stream EXTDTA objects.\r
+ * The InputStream uses this DDMReader to read data from network. The \r
+ * DDMReader should not be used before all data in the stream has been read.\r
+ * @param checkNullability used to check if the stream is null. If it is \r
+ * null, this method returns null\r
+ * @return EXTDTAReaderInputStream object which can be passed to prepared\r
+ * statement as a binary stream.\r
+ * @exception DRDAProtocolException standard DRDA protocol exception\r
+ */\r
+ EXTDTAReaderInputStream getEXTDTAReaderInputStream\r
+ (final boolean checkNullability)\r
+ throws DRDAProtocolException\r
+ {\r
+ if (checkNullability && isEXTDTANull()) {\r
+ return null;\r
+ \r
+ } else if ( doingLayerBStreaming ){\r
+ return new LayerBStreamedEXTDTAReaderInputStream(this);\r
+ \r
+ } else {\r
+ return new StandardEXTDTAReaderInputStream(this);\r
+ \r
+ }\r
+\r
+ }\r
+ \r
+ /**\r
+ * This method is used by EXTDTAReaderInputStream to read the first chunk \r
+ * of data.\r
+ * This lengthless method must be called only when layer B streaming.\r
+ *\r
+ * @exception DRDAProtocolException standard DRDA protocol exception\r
+ */\r
+ ByteArrayInputStream readLOBInitStream() \r
+ throws DRDAProtocolException\r
+ {\r
+ if ( SanityManager.DEBUG ) {\r
+ SanityManager.ASSERT( doingLayerBStreaming );\r
+ }\r
+ \r
+ return readLOBInitStream( 0 );\r
+ \r
+ }\r
+ \r
+\r
+ /**\r
+ * This method is used by EXTDTAReaderInputStream to read the first chunk \r
+ * of data.\r
+ * @param desiredLength the desired length of chunk. This parameter is ignored when layerB Streaming is doing.\r
+ * @exception DRDAProtocolException standard DRDA protocol exception\r
+ */\r
+ ByteArrayInputStream readLOBInitStream(final long desiredLength) \r
+ throws DRDAProtocolException\r
+ {\r
+ return readLOBChunk(false, desiredLength);\r
+ }\r
+ \r
+ \r
+ /**\r
+ * This method is used by EXTDTAReaderInputStream to read the next chunk \r
+ * of data.\r
+ *\r
+ * Calling this method finishes layer B streaming \r
+ * if continuation of DSS segment was finished.\r
+ * This lengthless method must be called only when layer B streaming.\r
+ *\r
+ * @exception IOException IOException\r
+ */\r
+ ByteArrayInputStream readLOBContinuationStream ()\r
+ throws IOException\r
+ { \r
+ if ( SanityManager.DEBUG ) {\r
+ SanityManager.ASSERT( doingLayerBStreaming );\r
+ }\r
+ return readLOBContinuationStream( 0 );\r
+ }\r
+ \r
+\r
+ /**\r
+ * This method is used by EXTDTAReaderInputStream to read the next chunk \r
+ * of data.\r
+ *\r
+ * Furthermore, when Layer B streaming is carried out,\r
+ * calling this method finishes layer B streaming \r
+ * if continuation of DSS segment was finished.\r
+ *\r
+ * @param desiredLength the desired length of chunk. This parameter is ignored when layerB Streaming is doing.\r
+ * @exception IOException IOException\r
+ */\r
+ ByteArrayInputStream readLOBContinuationStream (final long desiredLength)\r
+ throws IOException\r
+ { \r
+ try {\r
+ return readLOBChunk(true, desiredLength);\r
+ } catch (DRDAProtocolException e) {\r
+ e.printStackTrace(agent.getServer().logWriter);\r
+ throw new IOException(e.getMessage());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * This method is used by EXTDTAReaderInputStream to read the next chunk \r
+ * of data.\r
+ *\r
+ * Furthermore, when Layer B streaming is carried out,\r
+ * calling this method may finish layer B streaming.\r
+ *\r
+ * @param readHeader set to true if the dss continuation should be read\r
+ * @param desiredLength the desired length of chunk. This parameter is ignored when layerB Streaming is doing.\r
+ * @exception DRDAProtocolException standard DRDA protocol exception\r
+ */\r
+ private ByteArrayInputStream readLOBChunk\r
+ (final boolean readHeader, final long desiredLength)\r
+ throws DRDAProtocolException\r
+ { \r
+ if (readHeader) { \r
+ readDSSContinuationHeader();\r
+ }\r
+ \r
+ int copySize = doingLayerBStreaming ? \r
+ dssLength : \r
+ (int) Math.min(dssLength, desiredLength);\r
+ \r
+ // read the segment\r
+ ensureALayerDataInBuffer (copySize);\r
+ \r
+ if( ! doingLayerBStreaming ){\r
+ adjustLengths (copySize);\r
+ \r
+ }else{\r
+ dssLength -= copySize;\r
+ \r
+ }\r
+ \r
+ // Create ByteArrayInputStream on top of buffer. \r
+ // This will not make a copy of the buffer.\r
+ ByteArrayInputStream bais = \r
+ new ByteArrayInputStream(buffer, pos, copySize);\r
+ pos += copySize;\r
+ \r
+ if( doingLayerBStreaming && \r
+ ! dssIsContinued )\r
+ finishLayerBStreaming();\r
+ \r
+ return bais;\r
+ }\r
+\r
+ byte[] getExtData (long desiredLength, boolean checkNullability) throws DRDAProtocolException\r
+ {\r
+\r
+ if ( SanityManager.DEBUG ) {\r
+ SanityManager.ASSERT( ! doingLayerBStreaming );\r
+ }\r
+\r
+ boolean readHeader;\r
+ int copySize;\r
+ ByteArrayOutputStream baos;\r
+ boolean isLengthAndNullabilityUnknown = false;\r
+\r
+ \r
+ if (desiredLength != -1) {\r
+ // allocate a stream based on a known amount of data\r
+ baos = new ByteArrayOutputStream ((int) desiredLength);\r
+ }\r
+ else {\r
+ // allocate a stream to hold an unknown amount of data\r
+ baos = new ByteArrayOutputStream ();\r
+ //isLengthAndNullabilityUnknown = true;\r
+ // If we aren't given a length get the whole thing.\r
+ desiredLength = MAX_EXTDTA_SIZE;\r
+ }\r
+ \r
+\r
+ // check for a null EXTDTA value, if it is nullable and if streaming\r
+ if (checkNullability)\r
+ if (isEXTDTANull())\r
+ return null;\r
+\r
+ // set the amount to read for the first segment\r
+ copySize = (int) Math.min(dssLength,desiredLength); //note: has already been adjusted for headers\r
+\r
+\r
+ //if (checkNullability) // don't count the null byte we've already read\r
+ //copySize--;\r
+\r
+ do {\r
+ // determine if a continuation header needs to be read after the data\r
+ if (dssIsContinued)\r
+ readHeader = true;\r
+ else\r
+ readHeader = false;\r
+\r
+ // read the segment\r
+ ensureALayerDataInBuffer (copySize);\r
+ adjustLengths (copySize);\r
+ baos.write (buffer, pos, copySize);\r
+ pos += copySize;\r
+ desiredLength -= copySize;\r
+\r
+ // read the continuation header, if necessary\r
+ if (readHeader)\r
+ readDSSContinuationHeader ();\r
+\r
+ copySize = (int) Math.min(dssLength,desiredLength); //note: has already been adjusted for headers\r
+\r
+ }\r
+ while (readHeader == true && desiredLength > 0);\r
+\r
+ return baos.toByteArray();\r
+ }\r
+\r
+\r
+ // reads a DSS continuation header\r
+ // prereq: pos is positioned on the first byte of the two-byte header\r
+ // post: dssIsContinued is set to true if the continuation bit is on, false otherwise\r
+ // dssLength is set to DssConstants.MAXDSS_LEN - 2 (don't count the header for the next read)\r
+ // helper method for getEXTDTAData\r
+ private void readDSSContinuationHeader () throws DRDAProtocolException\r
+ {\r
+ ensureALayerDataInBuffer(2);\r
+\r
+ dssLength =\r
+ ((buffer[pos++]&0xFF) << 8) +\r
+ ((buffer[pos++]&0xFF) << 0);\r
+\r
+ if ((dssLength & 0x8000) == 0x8000) {\r
+ dssLength = DssConstants.MAX_DSS_LENGTH;\r
+ dssIsContinued = true;\r
+ }\r
+ else {\r
+ dssIsContinued = false;\r
+ }\r
+ // it is a syntax error if the dss continuation header length\r
+ // is less than or equal to two\r
+ if (dssLength <= 2) {\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_DSS_CONT_LESS_OR_EQUAL_2,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+\r
+ dssLength -= 2; // avoid consuming the DSS cont header\r
+ }\r
+\r
+// checks the null EXTDTA byte\r
+ // returns true if null, false otherwise\r
+ // helper method for getEXTDTAData\r
+ private boolean isEXTDTANull () throws DRDAProtocolException\r
+ {\r
+ // make sure that the null byte is in the buffer\r
+ ensureALayerDataInBuffer (1);\r
+ adjustLengths (1);\r
+\r
+ // examine the null byte\r
+ byte nullByte = buffer[pos++];\r
+ if (nullByte == (byte)0x00)\r
+ return false;\r
+\r
+ return true;\r
+ }\r
+\r
+\r
+ /**\r
+ * Convert a range of packed nybbles (up to 9 digits without overflow) to an int.\r
+ * Note that for performance purpose, it does not do array-out-of-bound checking.\r
+ * @param buffer buffer to read from\r
+ * @param offset offset in the buffer\r
+ * @param startNybble start nybble\r
+ * @param numberOfNybbles number of nybbles\r
+ * @return an int value\r
+ */\r
+ private int packedNybblesToInt (byte[] buffer,\r
+ int offset,\r
+ int startNybble,\r
+ int numberOfNybbles)\r
+ {\r
+ int value = 0;\r
+\r
+ int i = startNybble / 2;\r
+ if ((startNybble % 2) != 0) {\r
+ // process low nybble of the first byte if necessary.\r
+ value += buffer[offset+i] & 0x0F;\r
+ i++;\r
+ }\r
+\r
+ int endNybble = startNybble + numberOfNybbles -1;\r
+ for (; i<(endNybble+1)/2; i++) {\r
+ value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4); // high nybble.\r
+ value = value*10 + (buffer[offset+i] & 0x0F); // low nybble.\r
+ }\r
+\r
+ if ((endNybble % 2) == 0) {\r
+ // process high nybble of the last byte if necessary.\r
+ value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4);\r
+ }\r
+\r
+ return value;\r
+ }\r
+\r
+ /**\r
+ * Convert a range of packed nybbles (up to 18 digits without overflow) to a long.\r
+ * Note that for performance purpose, it does not do array-out-of-bound checking.\r
+ * @param buffer buffer to read from\r
+ * @param offset offset in the buffer\r
+ * @param startNybble start nybble\r
+ * @param numberOfNybbles number of nybbles\r
+ * @return an long value\r
+ */\r
+ private long packedNybblesToLong (byte[] buffer,\r
+ int offset,\r
+ int startNybble,\r
+ int numberOfNybbles)\r
+ {\r
+ long value = 0;\r
+\r
+ int i = startNybble / 2;\r
+ if ((startNybble % 2) != 0) {\r
+ // process low nybble of the first byte if necessary.\r
+ value += buffer[offset+i] & 0x0F;\r
+ i++;\r
+ }\r
+\r
+ int endNybble = startNybble + numberOfNybbles -1;\r
+ for (; i<(endNybble+1)/2; i++) {\r
+ value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4); // high nybble.\r
+ value = value*10 + (buffer[offset+i] & 0x0F); // low nybble.\r
+ }\r
+\r
+ if ((endNybble % 2) == 0) {\r
+ // process high nybble of the last byte if necessary.\r
+ value = value*10 + ((buffer[offset+i] & 0xF0) >>> 4);\r
+ }\r
+\r
+ return value;\r
+ }\r
+\r
+ /**\r
+ * Compute the int array of magnitude from input value segments.\r
+ * @param input value segments\r
+ * @return array of int magnitudes\r
+ */\r
+ private int[] computeMagnitude(int[] input)\r
+ {\r
+ int length = input.length;\r
+ int[] mag = new int[length];\r
+\r
+ mag[length-1] = input[length-1];\r
+ for (int i=0; i<length-1; i++) {\r
+ int carry = 0;\r
+ int j = tenRadixMagnitude[i].length-1;\r
+ int k = length-1;\r
+ for (; j>=0; j--, k--) {\r
+ long product = (input[length-2-i] & 0xFFFFFFFFL) * (tenRadixMagnitude[i][j] & 0xFFFFFFFFL)\r
+ + (mag[k] & 0xFFFFFFFFL) // add previous value\r
+ + (carry & 0xFFFFFFFFL); // add carry\r
+ carry = (int) (product >>> 32);\r
+ mag[k] = (int) (product & 0xFFFFFFFFL);\r
+ }\r
+ mag[k] = (int) carry;\r
+ }\r
+ return mag;\r
+ }\r
+\r
+ /**\r
+ * Read boolean value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected boolean readBoolean () throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (1, ADJUST_LENGTHS);\r
+ return buffer[pos++] != 0;\r
+ }\r
+\r
+ /**\r
+ * Read encrypted string\r
+ * @param decryptM decryption manager\r
+ * @param securityMechanism security mechanism\r
+ * @param initVector initialization vector for cipher\r
+ * @param sourcePublicKey public key (as in Deffie-Hellman algorithm)\r
+ * from source (encryptor)\r
+ * @return decrypted string\r
+ *\r
+ * @exception DRDProtocolException, SQLException(wrapping any exception in decryption)\r
+ */\r
+ protected String readEncryptedString (DecryptionManager decryptM, int securityMechanism,\r
+ byte[] initVector, byte[] sourcePublicKey)\r
+ throws DRDAProtocolException, java.sql.SQLException\r
+ {\r
+ byte[] cipherText = readBytes();\r
+ byte[] plainText = null;\r
+ plainText = decryptM.decryptData(cipherText, securityMechanism, initVector,\r
+ sourcePublicKey);\r
+ if (plainText == null)\r
+ return null;\r
+ else\r
+ return ccsidManager.convertToUCS2(plainText);\r
+ }\r
+\r
+ /**\r
+ * Read string value\r
+ * Strings in DRDA protocol are encoded in EBCDIC by default so we\r
+ * need to convert to UCS2\r
+ * @param length - length of string to read\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readString (int length) throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (length, ADJUST_LENGTHS);\r
+\r
+ String result = ccsidManager.convertToUCS2 (buffer, pos, length);\r
+ pos += length;\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Read string value into a <code>DRDAString</code> object.\r
+ *\r
+ * @param dst destination for the read string\r
+ * @param size size (in bytes) of string to read\r
+ * @param unpad if true, remove padding (trailing spaces)\r
+ *\r
+ * @exception DRDAProtocolException\r
+ */\r
+ protected void readString(DRDAString dst, int size, boolean unpad)\r
+ throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer(size, ADJUST_LENGTHS);\r
+ int startPos = pos;\r
+ pos += size;\r
+ if (unpad) {\r
+ while ((size > 0) &&\r
+ (buffer[startPos + size - 1] == ccsidManager.space)) {\r
+ --size;\r
+ }\r
+ }\r
+ dst.setBytes(buffer, startPos, size);\r
+ }\r
+\r
+ /**\r
+ * Read encoded string value\r
+ * @param length - length of string to read\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readString (int length, String encoding) \r
+ throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (length, ADJUST_LENGTHS);\r
+ String s = null;\r
+\r
+ try {\r
+ s = new String (buffer, pos, length, encoding);\r
+ }\r
+ catch (java.io.UnsupportedEncodingException e) {\r
+ agent.agentError("UnsupportedEncodingException in readString, encoding = " \r
+ + encoding);\r
+ e.printStackTrace(agent.getServer().logWriter);\r
+ }\r
+ \r
+ pos += length;\r
+ return s;\r
+ }\r
+\r
+ /**\r
+ * Read string value in DDM data with default encoding\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readStringData()\r
+ throws DRDAProtocolException\r
+ {\r
+ return readString((int)ddmScalarLen, NetworkServerControlImpl.DEFAULT_ENCODING);\r
+ }\r
+\r
+ /**\r
+ * Read specified length of string value in DDM data with default encoding\r
+ * @param length - length of string to read\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readStringData(int length)\r
+ throws DRDAProtocolException\r
+ {\r
+ return readString(length, NetworkServerControlImpl.DEFAULT_ENCODING);\r
+ }\r
+\r
+ /**\r
+ * Read length delimited string value in DDM data with default encoding\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readLDStringData(String encoding)\r
+ throws DRDAProtocolException\r
+ {\r
+ int length = readNetworkShort();\r
+ return readString(length, encoding);\r
+ }\r
+\r
+ /**\r
+ * Read string value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readString () throws DRDAProtocolException\r
+ {\r
+ return readString((int)ddmScalarLen);\r
+ }\r
+\r
+ /**\r
+ * Read byte string value\r
+ * @param length - length of string to read\r
+ * @return byte array\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected byte[] readBytes (int length) throws DRDAProtocolException\r
+ {\r
+ byte[] b;\r
+\r
+ if (length < DssConstants.MAX_DSS_LENGTH)\r
+ {\r
+ ensureBLayerDataInBuffer (length, ADJUST_LENGTHS);\r
+ b = new byte[length];\r
+ System.arraycopy(buffer,pos,b,0,length);\r
+ pos +=length;\r
+ }\r
+ else\r
+ b = getExtData(length,false);\r
+ return b;\r
+ }\r
+ \r
+ /**\r
+ * Read byte string value\r
+ * @return byte array\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected byte[] readBytes () throws DRDAProtocolException\r
+ {\r
+ return readBytes((int)ddmScalarLen);\r
+ }\r
+\r
+ /**\r
+ * Skip byte string value\r
+ * @param length - length of string to skip\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected void skipBytes (int length) throws DRDAProtocolException\r
+ {\r
+ ensureBLayerDataInBuffer (length, ADJUST_LENGTHS);\r
+ pos += length;\r
+ }\r
+\r
+ /**\r
+ * Skip byte string value\r
+ *\r
+ * @exception DRDAProtocolException\r
+ */\r
+ protected void skipBytes () throws DRDAProtocolException\r
+ {\r
+ skipBytes((int)ddmScalarLen);\r
+ }\r
+\r
+ /**\r
+ * Skip remaining DSS\r
+ *\r
+ * @exception DRDAProtocolException\r
+ */\r
+ protected void skipDss() throws DRDAProtocolException\r
+ {\r
+ while (dssIsContinued)\r
+ {\r
+ skipBytes((int)dssLength);\r
+ readDSSContinuationHeader();\r
+ }\r
+ skipBytes((int)dssLength);\r
+ topDdmCollectionStack = EMPTY_STACK;\r
+ ddmScalarLen = 0;\r
+ dssLength = 0;\r
+\r
+ }\r
+\r
+ protected void clearBuffer() throws DRDAProtocolException\r
+ {\r
+ skipBytes(java.lang.Math.min(dssLength, count - pos));\r
+ dssIsChainedWithSameID = false;\r
+ dssIsChainedWithDiffID = false;\r
+ }\r
+\r
+ /**\r
+ * Convert EBCDIC byte array to unicode string\r
+ *\r
+ * @param buf - byte array\r
+ * @return string\r
+ */\r
+ protected String convertBytes(byte[] buf)\r
+ {\r
+ return ccsidManager.convertToUCS2 (buf, 0, buf.length);\r
+ }\r
+\r
+ // Private methods\r
+ /**\r
+ * Adjust remaining length\r
+ *\r
+ * @param length - adjustment length\r
+ */\r
+ private void adjustLengths(int length)\r
+ {\r
+ ddmScalarLen -= length;\r
+ for (int i = 0; i <= topDdmCollectionStack; i++) {\r
+ ddmCollectionLenStack[i] -= length;\r
+ }\r
+ dssLength -= length;\r
+ }\r
+\r
+ /********************************************************************/\r
+ /* NetworkServerControl command protocol reading routines \r
+ */\r
+ /********************************************************************/\r
+ /**\r
+ * Read string value\r
+ * @param length - length of string to read\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readCmdString (int length) throws DRDAProtocolException, java.io.UnsupportedEncodingException\r
+ {\r
+ if (length == 0)\r
+ return null;\r
+\r
+ ensureBLayerDataInBuffer (length, ADJUST_LENGTHS);\r
+ String result = new String (buffer, pos, length,\r
+ NetworkServerControlImpl.DEFAULT_ENCODING);\r
+ pos += length;\r
+ return result;\r
+ }\r
+ /**\r
+ * Read string value\r
+ * @return value\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ protected String readCmdString () throws DRDAProtocolException, java.io.UnsupportedEncodingException\r
+ {\r
+ int length = readNetworkShort();\r
+ return readCmdString(length);\r
+ \r
+ }\r
+\r
+ /**************************************************************************/\r
+ /* Private methods\r
+ /**************************************************************************/\r
+ /**\r
+ * Make sure a certain amount of Layer A data is in the buffer.\r
+ * The data will be in the buffer after this method is called.\r
+ *\r
+ * @param desiredDataSize - amount of data we need\r
+ *\r
+ * @exception DRDAProtocolException\r
+ */\r
+ private void ensureALayerDataInBuffer (int desiredDataSize) \r
+ throws DRDAProtocolException\r
+ {\r
+ // calulate the the number of bytes in the buffer.\r
+ int avail = count - pos;\r
+\r
+ // read more bytes off the network if the data is not in the buffer already.\r
+ if (avail < desiredDataSize) \r
+ {\r
+ fill (desiredDataSize - avail);\r
+ }\r
+ }\r
+ /**\r
+ * Make sure a certain amount of Layer B data is in the buffer.\r
+ * The data will be in the buffer after this method is called.\r
+ *\r
+ * @param desiredDataSize - amount of data we need\r
+ * @param adjustLen - whether to adjust the remaining lengths\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ private void ensureBLayerDataInBuffer (int desiredDataSize, boolean adjustLen) \r
+ throws DRDAProtocolException\r
+ {\r
+ ensureALayerDataInBuffer (desiredDataSize);\r
+ if (dssIsContinued) \r
+ {\r
+ if (desiredDataSize > dssLength) \r
+ {\r
+ int continueDssHeaderCount =\r
+ (((desiredDataSize - dssLength) / DssConstants.MAX_DSS_LENGTH) + 1);\r
+ compressBLayerData (continueDssHeaderCount);\r
+ }\r
+ }\r
+ if (adjustLen)\r
+ adjustLengths(desiredDataSize);\r
+ }\r
+\r
+ /**\r
+ * Compress B Layer data if extended total length is used\r
+ * by removing the continuation headers\r
+ *\r
+ * @param continueDssHeaderCount - amount of data we need\r
+ *\r
+ * @exception throws DRDAProtocolException\r
+ */\r
+ private void compressBLayerData (int continueDssHeaderCount) \r
+ throws DRDAProtocolException\r
+ {\r
+\r
+ \r
+ // jump to the last continuation header.\r
+ int tempPos = 0;\r
+ for (int i = 0; i < continueDssHeaderCount; i++) \r
+ {\r
+ // the first may be less than the size of a full DSS\r
+ if (i == 0) \r
+ {\r
+ // only jump by the number of bytes remaining in the current DSS\r
+ tempPos = pos + dssLength;\r
+ }\r
+ else \r
+ {\r
+ // all other jumps are for a full continued DSS\r
+ tempPos += DssConstants.MAX_DSS_LENGTH;\r
+ }\r
+ }\r
+\r
+\r
+ // for each of the DSS headers to remove,\r
+ // read out the continuation header and increment the DSS length by the\r
+ // size of the continuation bytes, then shift the continuation data as needed.\r
+ int shiftSize = 0;\r
+ int bytesToShift = 0;\r
+ int continueHeaderLength = 0;\r
+ int newdssLength = 0;\r
+\r
+\r
+ for (int i = 0; i < continueDssHeaderCount; i++) \r
+ {\r
+ continueHeaderLength = ((buffer[tempPos] & 0xff) << 8) +\r
+ ((buffer[tempPos + 1] & 0xff) << 0);\r
+\r
+ if (i == 0) \r
+ {\r
+ // if this is the last one (farthest down stream and first to strip out)\r
+\r
+ if ((continueHeaderLength & DssConstants.CONTINUATION_BIT) \r
+ == DssConstants.CONTINUATION_BIT)\r
+ {\r
+ // the last DSS header is again continued\r
+ continueHeaderLength = DssConstants.MAX_DSS_LENGTH;\r
+ dssIsContinued = true;\r
+ }\r
+ else \r
+ {\r
+ // the last DSS header was not contiued so update continue state flag\r
+ dssIsContinued = false;\r
+ }\r
+ // the very first shift size is 2\r
+ shiftSize = 2;\r
+ }\r
+ else \r
+ {\r
+ // already removed the last header so make sure the chaining flag is on\r
+ if ((continueHeaderLength & DssConstants.CONTINUATION_BIT) == \r
+ DssConstants.CONTINUATION_BIT)\r
+ {\r
+ continueHeaderLength = DssConstants.MAX_DSS_LENGTH;\r
+ }\r
+ else \r
+ {\r
+ // this is a syntax error but not really certain which one.\r
+ // for now pick 0x02 which is DSS header Length does not \r
+ // match the number\r
+ // of bytes of data found.\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_DSS_LENGTH_BYTE_NUMBER_MISMATCH,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+ // increase the shift size by 2\r
+ shiftSize += 2;\r
+ }\r
+\r
+ // it is a syntax error if the DSS continuation is less \r
+ // than or equal to two\r
+ if (continueHeaderLength <= 2) \r
+ {\r
+ agent.throwSyntaxrm(CodePoint.SYNERRCD_DSS_CONT_LESS_OR_EQUAL_2,\r
+ DRDAProtocolException.NO_CODPNT_ARG);\r
+ }\r
+\r
+ newdssLength += (continueHeaderLength-2);\r
+\r
+ // calculate the number of bytes to shift\r
+ if (i != (continueDssHeaderCount - 1))\r
+ bytesToShift = DssConstants.MAX_DSS_LENGTH;\r
+ else\r
+ bytesToShift = dssLength;\r
+\r
+ tempPos -= (bytesToShift - 2);\r
+ System.arraycopy(buffer, tempPos - shiftSize, buffer, tempPos,\r
+ bytesToShift);\r
+ }\r
+ // reposition the start of the data after the final DSS shift.\r
+ pos = tempPos;\r
+ dssLength += newdssLength;\r
+ }\r
+\r
+ /**\r
+ * Methods to manage the data buffer.\r
+ * Methods orginally from JCC\r
+ * RESOLVE: need to check if this is the best performing way of doing this\r
+ */\r
+\r
+ /**\r
+ * This is a helper method which shifts the buffered bytes from\r
+ * wherever they are in the current buffer to the beginning of\r
+ * different buffer (note these buffers could be the same).\r
+ * State information is updated as needed after the shift.\r
+ * @param destinationBuffer - buffer to shift data to\r
+ */\r
+ private void shiftBuffer (byte[] destinationBuffer)\r
+ {\r
+ // calculate the size of the data in the current buffer.\r
+ int sz = count - pos;\r
+ if (SanityManager.DEBUG) {\r
+ if ((sz < 0 || pos < 0) )\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected data size or position. sz=" + sz + \r
+ " count=" + count +" pos=" + pos);\r
+ }\r
+ }\r
+ \r
+ // copy this data to the new buffer startsing at position 0.\r
+ System.arraycopy (buffer, pos, destinationBuffer, 0, sz);\r
+\r
+ // update the state information for data in the new buffer.\r
+ pos = 0;\r
+ count = sz;\r
+\r
+ // replace the old buffer with the new buffer.\r
+ buffer = destinationBuffer;\r
+ }\r
+ /**\r
+ * This method makes sure there is enough room in the buffer\r
+ * for a certain number of bytes. This method will allocate\r
+ * a new buffer if needed and shift the bytes in the current buffer\r
+ * to make ensure space is available for a fill. Right now\r
+ * this method will shift bytes as needed to make sure there is\r
+ * as much room as possible in the buffer before trying to\r
+ * do the read. The idea is to try to have space to get as much data as possible\r
+ * if we need to do a read on the socket's stream.\r
+ *\r
+ * @param desiredSpace - amount of data we need\r
+ */\r
+ private void ensureSpaceInBufferForFill (int desiredSpace)\r
+ {\r
+ // calculate the total unused space in the buffer.\r
+ // this includes any space at the end of the buffer and any free\r
+ // space at the beginning resulting from bytes already read.\r
+ int currentAvailableSpace = (buffer.length - count) + pos;\r
+\r
+ // check to see if there is enough free space.\r
+ if (currentAvailableSpace < desiredSpace) {\r
+\r
+ // there is not enough free space so we need more storage.\r
+ // we are going to double the buffer unless that happens to still be \r
+ // too small. If more than double the buffer is needed, \r
+ // use the smallest amount over this as possible.\r
+ int doubleBufferSize = (2 * buffer.length);\r
+ int minumNewBufferSize = (desiredSpace - currentAvailableSpace) + \r
+ buffer.length;\r
+ int newsz = minumNewBufferSize <= doubleBufferSize ? \r
+ doubleBufferSize : minumNewBufferSize;\r
+\r
+ byte[] newBuffer = new byte[newsz];\r
+\r
+ // shift everything from the old buffer to the new buffer\r
+ shiftBuffer (newBuffer);\r
+ }\r
+ else {\r
+\r
+ // there is enough free space in the buffer but let's make sure\r
+ // it is all at the end.\r
+ // this is also important because if we are going to do a read, \r
+ // it would be nice\r
+ // to get as much data as possible and making room at the end \r
+ // if the buffer helps to ensure this.\r
+ if (pos != 0) {\r
+ shiftBuffer (buffer);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * This method will attempt to read a minimum number of bytes\r
+ * from the underlying stream. This method will keep trying to\r
+ * read bytes until it has obtained at least the minimum number.\r
+ * @param minimumBytesNeeded - minimum required bytes\r
+ *\r
+ * @exception DRDProtocolException\r
+ */\r
+ private void fill (int minimumBytesNeeded) throws DRDAProtocolException\r
+ {\r
+ // make sure that there is enough space in the buffer to hold\r
+ // the minimum number of bytes needed.\r
+ ensureSpaceInBufferForFill (minimumBytesNeeded);\r
+\r
+ // read until the minimum number of bytes needed is now in the buffer.\r
+ // hopefully the read method will return as many bytes as it can.\r
+ int totalBytesRead = 0;\r
+ int actualBytesRead = 0;\r
+ do {\r
+ try {\r
+ actualBytesRead = inputStream.read (//waiting for client request on the socket\r
+ buffer, count, buffer.length - count);\r
+ } catch (java.net.SocketTimeoutException ste) {\r
+\r
+ // Transport the timeout out through the layers. This\r
+ // exception is caught in DRDAConnThread.run();\r
+ throw new DRDASocketTimeoutException(agent);\r
+\r
+ } catch (java.io.IOException ioe) {\r
+ agent.markCommunicationsFailure("DDMReader.fill()",\r
+ "InputStream.read()", ioe.getMessage(), "*");\r
+ } finally {\r
+ if ((dssTrace != null) && dssTrace.isComBufferTraceOn())\r
+ dssTrace.writeComBufferData (buffer,\r
+ count,\r
+ actualBytesRead,\r
+ DssTrace.TYPE_TRACE_RECEIVE,\r
+ "Request",\r
+ "fill",\r
+ 5);\r
+ }\r
+ if (actualBytesRead != -1)\r
+ {\r
+ count += actualBytesRead;\r
+ totalBytesRead += actualBytesRead;\r
+ }\r
+\r
+ } while ((totalBytesRead < minimumBytesNeeded) && (actualBytesRead != -1));\r
+\r
+ if (actualBytesRead == -1) \r
+ {\r
+ if (totalBytesRead < minimumBytesNeeded) \r
+ {\r
+ agent.markCommunicationsFailure ("DDMReader.fill()",\r
+ "InputStream.read()", "insufficient data", "*");\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Print a internal trace message\r
+ */\r
+ private void trace(String msg)\r
+ {\r
+ if (agent != null)\r
+ agent.trace(msg);\r
+ }\r
+\r
+ protected String toDebugString(String indent)\r
+ {\r
+ String s = indent + "***** DDMReader toDebugString ******\n";\r
+ int buflen = 0;\r
+ if (buffer != null)\r
+ buflen = buffer.length;\r
+ s += indent + "Reader buffer length = " + buffer.length + "\n";\r
+ return s;\r
+ }\r
+\r
+ /**\r
+ * Return chaining bit for current DSS.\r
+ */\r
+ protected byte getCurrChainState() {\r
+\r
+ if (!dssIsChainedWithSameID && !dssIsChainedWithDiffID)\r
+ return DssConstants.DSS_NOCHAIN;\r
+\r
+ if (dssIsChainedWithSameID)\r
+ return DssConstants.DSSCHAIN_SAME_ID;\r
+\r
+ return DssConstants.DSSCHAIN;\r
+\r
+ }\r
+ \r
+ \r
+ private void startLayerBStreaming() {\r
+ doingLayerBStreaming = true;\r
+ }\r
+ \r
+ \r
+ private void finishLayerBStreaming() {\r
+ doingLayerBStreaming = false;\r
+ }\r
+ \r
+ \r
+ boolean doingLayerBStreaming() {\r
+ return doingLayerBStreaming;\r
+ }\r
+ \r
+ \r
+}\r