0001: /*
0002:
0003: Derby - Class org.apache.derby.client.net.Reply
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to You under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.client.net;
0023:
0024: import java.io.ByteArrayOutputStream;
0025: import java.util.Arrays;
0026:
0027: import org.apache.derby.client.am.SignedBinary;
0028: import org.apache.derby.client.am.SqlException;
0029: import org.apache.derby.client.am.DisconnectException;
0030: import org.apache.derby.client.am.SqlState;
0031: import org.apache.derby.client.am.ClientMessageId;
0032:
0033: import org.apache.derby.shared.common.reference.SQLState;
0034: import org.apache.derby.shared.common.reference.MessageId;
0035:
0036: public class Reply {
0037: protected org.apache.derby.client.am.Agent agent_;
0038: protected NetAgent netAgent_; //cheat-link to (NetAgent) agent_
0039:
0040: private CcsidManager ccsidManager_;
0041: protected final static int DEFAULT_BUFFER_SIZE = 32767;
0042: protected byte[] buffer_;
0043: protected int pos_;
0044: protected int count_;
0045:
0046: private int topDdmCollectionStack_;
0047: private final static int MAX_MARKS_NESTING = 10;
0048: private int[] ddmCollectionLenStack_;
0049: private int ddmScalarLen_; // a value of -1 -> streamed ddm -> length unknown
0050: private final static int EMPTY_STACK = -1;
0051:
0052: protected boolean ensuredLengthForDecryption_ = false; // A layer lengths have already been ensured in decrypt method.
0053: protected byte[] longBufferForDecryption_ = null;
0054: protected int longPosForDecryption_ = 0;
0055: protected byte[] longValueForDecryption_ = null;
0056: protected int longCountForDecryption_ = 0;
0057:
0058: protected int dssLength_;
0059: protected boolean dssIsContinued_;
0060: private boolean dssIsChainedWithSameID_;
0061: private boolean dssIsChainedWithDiffID_;
0062: protected int dssCorrelationID_;
0063:
0064: protected int peekedLength_ = 0;
0065: protected int peekedCodePoint_ = END_OF_COLLECTION; // saves the peeked codept
0066: private int peekedNumOfExtendedLenBytes_ = 0;
0067: private int currentPos_ = 0;
0068:
0069: public final static int END_OF_COLLECTION = -1;
0070: public final static int END_OF_SAME_ID_CHAIN = -2;
0071:
0072: Reply(NetAgent netAgent, int bufferSize) {
0073: buffer_ = new byte[bufferSize];
0074: agent_ = netAgent_ = netAgent;
0075: ccsidManager_ = netAgent.targetCcsidManager_;
0076: ddmCollectionLenStack_ = new int[Reply.MAX_MARKS_NESTING];
0077: initialize();
0078: }
0079:
0080: final void initialize() {
0081: pos_ = 0;
0082: count_ = 0;
0083: topDdmCollectionStack_ = Reply.EMPTY_STACK;
0084: Arrays.fill(ddmCollectionLenStack_, 0);
0085: ddmScalarLen_ = 0;
0086: dssLength_ = 0;
0087: dssIsContinued_ = false;
0088: dssIsChainedWithSameID_ = false;
0089: dssIsChainedWithDiffID_ = false;
0090: dssCorrelationID_ = 1;
0091: }
0092:
0093: final int getDdmLength() {
0094: return ddmScalarLen_;
0095: }
0096:
0097: // This is a helper method which shifts the buffered bytes from
0098: // wherever they are in the current buffer to the beginning of
0099: // different buffer (note these buffers could be the same).
0100: // State information is updated as needed after the shift.
0101: private final void shiftBuffer(byte[] destinationBuffer) {
0102: // calculate the size of the data in the current buffer.
0103: int sz = count_ - pos_;
0104:
0105: // copy this data to the new buffer starting at position 0.
0106: System.arraycopy(buffer_, pos_, destinationBuffer, 0, sz);
0107:
0108: // update the state information for data in the new buffer.
0109: pos_ = 0;
0110: count_ = sz;
0111:
0112: // replace the old buffer with the new buffer.
0113: buffer_ = destinationBuffer;
0114: }
0115:
0116: // This method makes sure there is enough room in the buffer
0117: // for a certain number of bytes. This method will allocate
0118: // a new buffer if needed and shift the bytes in the current buffer
0119: // to make ensure space is available for a fill. Right now
0120: // this method will shift bytes as needed to make sure there is
0121: // as much room as possible in the buffer before trying to
0122: // do the read. The idea is to try to have space to get as much data as possible
0123: // if we need to do a read on the socket's stream.
0124: protected final void ensureSpaceInBufferForFill(int desiredSpace) {
0125: // calculate the total unused space in the buffer.
0126: // this includes any space at the end of the buffer and any free
0127: // space at the beginning resulting from bytes already read.
0128: int currentAvailableSpace = (buffer_.length - count_) + pos_;
0129:
0130: // check to see if there is enough free space.
0131: if (currentAvailableSpace < desiredSpace) {
0132:
0133: // there is not enough free space so we need more storage.
0134: // we are going to double the buffer unless that happens to still be too small.
0135: // if more than double the buffer is needed, use the smallest amount over this as possible.
0136: int doubleBufferSize = (2 * buffer_.length);
0137:
0138: int minumNewBufferSize = (desiredSpace - currentAvailableSpace)
0139: + buffer_.length;
0140: int newsz = minumNewBufferSize <= doubleBufferSize ? doubleBufferSize
0141: : minumNewBufferSize;
0142:
0143: byte[] newBuffer = new byte[newsz];
0144:
0145: // shift everything from the old buffer to the new buffer
0146: shiftBuffer(newBuffer);
0147: } else {
0148:
0149: // there is enough free space in the buffer but let's make sure it is all at the end.
0150: // this is also important because if we are going to do a read, it would be nice
0151: // to get as much data as possible and making room at the end if the buffer helps to
0152: // ensure this.
0153: if (pos_ != 0) {
0154: shiftBuffer(buffer_);
0155: }
0156: }
0157: }
0158:
0159: // This method will attempt to read a minimum number of bytes
0160: // from the underlying stream. This method will keep trying to
0161: // read bytes until it has obtained at least the minimum number.
0162: // Now returns the total bytes read for decryption, use to return void.
0163: protected int fill(int minimumBytesNeeded)
0164: throws DisconnectException {
0165: // make sure that there is enough space in the buffer to hold
0166: // the minimum number of bytes needed.
0167: ensureSpaceInBufferForFill(minimumBytesNeeded);
0168:
0169: // read until the minimum number of bytes needed is now in the buffer.
0170: // hopefully the read method will return as many bytes as it can.
0171: int totalBytesRead = 0;
0172: int actualBytesRead = 0;
0173: do {
0174: try {
0175: // oops, we shouldn't expose the agent's input stream here, collapse this into a read method on the agent
0176: actualBytesRead = netAgent_.getInputStream().read(
0177: buffer_, count_, buffer_.length - count_);
0178: } catch (java.io.IOException ioe) {
0179: netAgent_.throwCommunicationsFailure(ioe);
0180: } finally {
0181: if (agent_.loggingEnabled()) {
0182: ((NetLogWriter) netAgent_.logWriter_)
0183: .traceProtocolFlow(buffer_, count_,
0184: actualBytesRead,
0185: NetLogWriter.TYPE_TRACE_RECEIVE,
0186: "Reply", "fill", 2); // tracepoint
0187: }
0188: }
0189: count_ += actualBytesRead;
0190: totalBytesRead += actualBytesRead;
0191:
0192: } while ((totalBytesRead < minimumBytesNeeded)
0193: && (actualBytesRead != -1));
0194:
0195: if (actualBytesRead == -1) {
0196: if (totalBytesRead < minimumBytesNeeded) {
0197: netAgent_
0198: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
0199: netAgent_,
0200: new ClientMessageId(
0201: SQLState.NET_INSUFFICIENT_DATA),
0202: new Integer(minimumBytesNeeded),
0203: new Integer(totalBytesRead)));
0204: }
0205: }
0206: return totalBytesRead;
0207: }
0208:
0209: // Make sure a certain amount of Layer A data is in the buffer.
0210: // The data will be in the buffer after this method is called.
0211: // Now returns the total bytes read for decryption, use to return void.
0212: protected final int ensureALayerDataInBuffer(int desiredDataSize)
0213: throws DisconnectException {
0214: int totalBytesRead = 0;
0215: // calulate the the number of bytes in the buffer.
0216: int avail = count_ - pos_;
0217:
0218: // read more bytes off the network if the data is not in the buffer already.
0219: if (avail < desiredDataSize) {
0220: totalBytesRead = fill(desiredDataSize - avail);
0221: }
0222: return totalBytesRead;
0223: }
0224:
0225: protected final void ensureBLayerDataInBuffer(int desiredDataSize)
0226: throws DisconnectException {
0227: if (dssIsContinued_ && (desiredDataSize > dssLength_)) {
0228: int continueDssHeaderCount = (((desiredDataSize - dssLength_) / 32767) + 1);
0229: ensureALayerDataInBuffer(desiredDataSize
0230: + (continueDssHeaderCount * 2));
0231: compressBLayerData(continueDssHeaderCount);
0232: return;
0233: }
0234: ensureALayerDataInBuffer(desiredDataSize);
0235: }
0236:
0237: // this will probably never be called.
0238: // it is included here in the highly unlikely event that a reply object
0239: // exceeds 32K. for opimization purposes, we should consider
0240: // removing this. removing this should be ok since we handle most
0241: // big stuff returned from the server (qrydta's for example) by
0242: // copying out the data into some other storage. any extended dss header
0243: // info will be removed in the copying process.
0244: private final void compressBLayerData(int continueDssHeaderCount)
0245: throws DisconnectException {
0246: int tempPos = 0;
0247:
0248: // jump to the last continuation header.
0249: for (int i = 0; i < continueDssHeaderCount; i++) {
0250: // the first may be less than the size of a full dss
0251: if (i == 0) {
0252: // only jump by the number of bytes remaining in the current dss
0253: tempPos = pos_ + dssLength_;
0254: } else {
0255: // all other jumps are for a full continued dss
0256: tempPos += 32767;
0257: }
0258: }
0259:
0260: // for each of the dss headers to remove,
0261: // read out the continuation header and increment the dss length by the
0262: // size of the conitnation bytes, then shift the continuation data as needed.
0263: int shiftSize = 0;
0264: int bytesToShift = 0;
0265: int continueHeaderLength = 0;
0266: int newDssLength = 0;
0267: for (int i = 0; i < continueDssHeaderCount; i++) {
0268:
0269: continueHeaderLength = ((buffer_[tempPos] & 0xFF) << 8)
0270: + ((buffer_[tempPos + 1] & 0xFF) << 0);
0271:
0272: if (i == 0) {
0273: // if this is the last one (farthest down stream and first to strip out)
0274:
0275: if ((continueHeaderLength & 0x8000) == 0x8000) {
0276: // the last dss header is again continued
0277: continueHeaderLength = 32767;
0278: dssIsContinued_ = true;
0279: } else {
0280: // the last dss header was not contiued so update continue state flag
0281: dssIsContinued_ = false;
0282: }
0283: // the very first shift size is 2
0284: shiftSize = 2;
0285: } else {
0286: // already removed the last header so make sure the chaining flag is on
0287: if ((continueHeaderLength & 0x8000) == 0x8000) {
0288: continueHeaderLength = 32767;
0289: } else {
0290: // this is a syntax error but not really certain which one.
0291: // for now pick 0x02 which is Dss header Length does not match the number
0292: // of bytes of data found.
0293: doSyntaxrmSemantics(CodePoint.SYNERRCD_DSS_LENGTH_BYTE_NUMBER_MISMATCH);
0294: }
0295: // increase the shift size by 2
0296: shiftSize += 2;
0297: }
0298:
0299: // it is a syntax error if the dss continuation is less than or equal to two
0300: if (continueHeaderLength <= 2) {
0301: doSyntaxrmSemantics(CodePoint.SYNERRCD_DSS_CONT_LESS_OR_EQUAL_2);
0302: }
0303:
0304: newDssLength += (continueHeaderLength - 2);
0305:
0306: // calculate the number of bytes to shift
0307: if (i != (continueDssHeaderCount - 1)) {
0308: bytesToShift = 32767;
0309: } else {
0310: bytesToShift = dssLength_;
0311: }
0312:
0313: tempPos -= (bytesToShift - 2);
0314: System.arraycopy(buffer_, tempPos - shiftSize, buffer_,
0315: tempPos, bytesToShift);
0316: }
0317: // reposition the start of the data after the final dss shift.
0318: pos_ = tempPos;
0319: dssLength_ = dssLength_ + newDssLength;
0320: }
0321:
0322: protected final void readDssHeader() throws DisconnectException {
0323: int correlationID = 0;
0324: int nextCorrelationID = 0;
0325: ensureALayerDataInBuffer(6);
0326:
0327: // read out the dss length
0328: dssLength_ = ((buffer_[pos_++] & 0xFF) << 8)
0329: + ((buffer_[pos_++] & 0xFF) << 0);
0330:
0331: // Remember the old dss length for decryption only.
0332: int oldDssLength = dssLength_;
0333:
0334: // check for the continuation bit and update length as needed.
0335: if ((dssLength_ & 0x8000) == 0x8000) {
0336: dssLength_ = 32767;
0337: dssIsContinued_ = true;
0338: } else {
0339: dssIsContinued_ = false;
0340: }
0341:
0342: if (dssLength_ < 6) {
0343: doSyntaxrmSemantics(CodePoint.SYNERRCD_DSS_LESS_THAN_6);
0344: }
0345:
0346: // If the GDS id is not valid, or
0347: // if the reply is not an RPYDSS nor
0348: // a OBJDSS, then throw an exception.
0349: if ((buffer_[pos_++] & 0xFF) != 0xd0) {
0350: doSyntaxrmSemantics(CodePoint.SYNERRCD_CBYTE_NOT_D0);
0351: }
0352:
0353: int gdsFormatter = buffer_[pos_++] & 0xFF;
0354: if (((gdsFormatter & 0x02) != 0x02)
0355: && ((gdsFormatter & 0x03) != 0x03)
0356: && ((gdsFormatter & 0x04) != 0x04)) {
0357: doSyntaxrmSemantics(CodePoint.SYNERRCD_FBYTE_NOT_SUPPORTED);
0358: }
0359:
0360: // Determine if the current DSS is chained with the
0361: // next DSS, with the same or different request ID.
0362: if ((gdsFormatter & 0x40) == 0x40) { // on indicates structure chained to next structure
0363: if ((gdsFormatter & 0x10) == 0x10) {
0364: dssIsChainedWithSameID_ = true;
0365: dssIsChainedWithDiffID_ = false;
0366: nextCorrelationID = dssCorrelationID_;
0367: } else {
0368: dssIsChainedWithSameID_ = false;
0369: dssIsChainedWithDiffID_ = true;
0370: nextCorrelationID = dssCorrelationID_ + 1;
0371: }
0372: } else {
0373: // chaining bit not b'1', make sure DSSFMT bit3 not b'1'
0374: if ((gdsFormatter & 0x10) == 0x10) { // Next DSS can not have same correlator
0375: doSyntaxrmSemantics(CodePoint.SYNERRCD_CHAIN_OFF_SAME_NEXT_CORRELATOR);
0376: }
0377:
0378: // chaining bit not b'1', make sure no error continuation
0379: if ((gdsFormatter & 0x20) == 0x20) { // must be 'do not continue on error'
0380: doSyntaxrmSemantics(CodePoint.SYNERRCD_CHAIN_OFF_ERROR_CONTINUE);
0381: }
0382:
0383: dssIsChainedWithSameID_ = false;
0384: dssIsChainedWithDiffID_ = false;
0385: nextCorrelationID = 1;
0386: }
0387:
0388: correlationID = ((buffer_[pos_++] & 0xFF) << 8)
0389: + ((buffer_[pos_++] & 0xFF) << 0);
0390:
0391: // corrid must be the one expected or a -1 which gets returned in some error cases.
0392: if ((correlationID != dssCorrelationID_)
0393: && (correlationID != 0xFFFF)) {
0394: doSyntaxrmSemantics(CodePoint.SYNERRCD_INVALID_CORRELATOR);
0395: } else {
0396: dssCorrelationID_ = nextCorrelationID;
0397: }
0398: dssLength_ -= 6;
0399: if ((gdsFormatter & 0x04) == 0x04) {
0400: decryptData(gdsFormatter, oldDssLength); //we have to decrypt data here because
0401: }
0402: //we need the decrypted codepoint. If
0403: //Data is very long > 32767, we have to
0404: //get all the data first because decrypt
0405: //piece by piece doesn't work.
0406: }
0407:
0408: private final void decryptData(int gdsFormatter, int oldDssLength)
0409: throws DisconnectException {
0410: boolean readHeader;
0411:
0412: if (dssLength_ == 32761) {
0413: ByteArrayOutputStream baos;
0414: int copySize = 0;
0415:
0416: baos = new ByteArrayOutputStream();
0417:
0418: // set the amount to read for the first segment
0419: copySize = dssLength_; // note: has already been adjusted for headers
0420:
0421: do {
0422: // determine if a continuation header needs to be read after the data
0423: if (dssIsContinued_) {
0424: readHeader = true;
0425: } else {
0426: readHeader = false;
0427: }
0428:
0429: // read the segment
0430: ensureALayerDataInBuffer(copySize);
0431: adjustLengths(copySize);
0432: baos.write(buffer_, pos_, copySize);
0433: pos_ += copySize;
0434:
0435: // read the continuation header, if necessary
0436: if (readHeader) {
0437: readDSSContinuationHeader();
0438: }
0439:
0440: copySize = dssLength_;
0441: } while (readHeader == true);
0442: byte[] cipherBytes = baos.toByteArray();
0443: byte[] clearedByte = null;
0444: try {
0445: clearedByte = netAgent_.netConnection_
0446: .getEncryptionManager().decryptData(
0447: cipherBytes,
0448: NetConfiguration.SECMEC_EUSRIDPWD,
0449: netAgent_.netConnection_
0450: .getTargetPublicKey(),
0451: netAgent_.netConnection_
0452: .getTargetPublicKey());
0453: } catch (SqlException e) {
0454: //throw new SqlException (agent_.logWriter_, "error in decrypting data");
0455: }
0456:
0457: //The decrypted data is for one codepoint only. We need to save the data follows this codepoint
0458: longBufferForDecryption_ = new byte[buffer_.length - pos_];
0459: longPosForDecryption_ = 0;
0460: count_ = count_ - pos_;
0461: longCountForDecryption_ = count_;
0462: System.arraycopy(buffer_, pos_, longBufferForDecryption_,
0463: 0, buffer_.length - pos_);
0464:
0465: //copy the clear data to buffer_
0466: if (clearedByte.length >= 32767) {
0467: System.arraycopy(clearedByte, 0, buffer_, 0, 32767);
0468: } else {
0469: System.arraycopy(clearedByte, 0, buffer_, 0,
0470: clearedByte.length);
0471: }
0472:
0473: pos_ = 0;
0474: dssLength_ = buffer_.length;
0475:
0476: int lobLength = 0;
0477: if (clearedByte.length > 32767) { //for extended length, length is the 4 bytes that follow codepoint
0478: lobLength = ((clearedByte[4] & 0xFF) << 24)
0479: + ((clearedByte[5] & 0xFF) << 16)
0480: + ((clearedByte[6] & 0xFF) << 8)
0481: + ((clearedByte[7] & 0xFF) << 0);
0482: longValueForDecryption_ = new byte[lobLength];
0483: System.arraycopy(clearedByte, 8,
0484: longValueForDecryption_, 0,
0485: clearedByte.length - 8);
0486: } else {
0487: lobLength = ((clearedByte[0] & 0xFF) << 8)
0488: + ((clearedByte[1] & 0xFF) << 0);
0489: longValueForDecryption_ = new byte[lobLength - 4];
0490: System.arraycopy(clearedByte, 4,
0491: longValueForDecryption_, 0,
0492: clearedByte.length - 4);
0493: }
0494: } else {
0495: int bytesRead = ensureALayerDataInBuffer(dssLength_); //we need to get back all the data here, and then decrypt
0496: if (bytesRead > 0) //we ensuredALayerDAtaInBuffer here and set the flag to true, so we don't need do this again later
0497: {
0498: ensuredLengthForDecryption_ = true;
0499: }
0500: byte[] encryptedByte = new byte[dssLength_];
0501: System.arraycopy(buffer_, pos_, encryptedByte, 0,
0502: dssLength_);
0503: byte[] array1 = new byte[pos_];
0504: System.arraycopy(buffer_, 0, array1, 0, pos_); //save the data before encrypted data in array1
0505: byte[] array3 = new byte[buffer_.length - dssLength_ - pos_];
0506: System.arraycopy(buffer_, pos_ + dssLength_, array3, 0,
0507: buffer_.length - dssLength_ - pos_); //save the data follows encrypted data in array3
0508: byte[] clearedByte = null;
0509: try {
0510: clearedByte = netAgent_.netConnection_
0511: .getEncryptionManager().decryptData(
0512: encryptedByte,
0513: NetConfiguration.SECMEC_EUSRIDPWD,
0514: netAgent_.netConnection_
0515: .getTargetPublicKey(),
0516: netAgent_.netConnection_
0517: .getTargetPublicKey());
0518: } catch (SqlException e) {
0519: //throw new SqlException (agent_.logWriter_, "error in decrypting data");
0520: }
0521: dssLength_ -= (encryptedByte.length - clearedByte.length);
0522: byte[] buffer = new byte[array1.length + clearedByte.length
0523: + array3.length];
0524: System.arraycopy(array1, 0, buffer, 0, array1.length);
0525: System.arraycopy(clearedByte, 0, buffer, array1.length,
0526: clearedByte.length);
0527: System.arraycopy(array3, 0, buffer, array1.length
0528: + clearedByte.length, array3.length);
0529: buffer_ = buffer;
0530: int oldCount = count_;
0531: count_ = count_
0532: - (encryptedByte.length - clearedByte.length);
0533: if (((clearedByte[2] & 0xff) << 8)
0534: + ((clearedByte[3] & 0xff) << 0) == 0x146c) {
0535: int firstLobLength = ((clearedByte[0] & 0xFF) << 8)
0536: + ((clearedByte[1] & 0xFF) << 0);
0537:
0538: boolean flag = false;
0539: if (gdsFormatter == 0x54) {
0540: flag = true;
0541: }
0542: if (flag) {
0543: if (oldCount - oldDssLength < 6) {
0544: int totalBytesRead = fill(6); //sometimes the 2nd EXTDTA doesn't come back, need to fetch again to get it
0545: if (totalBytesRead > 0) {
0546: longBufferForDecryption_ = new byte[totalBytesRead];
0547: longPosForDecryption_ = 0;
0548: System.arraycopy(buffer_, pos_
0549: + firstLobLength,
0550: longBufferForDecryption_, 0,
0551: totalBytesRead);
0552: }
0553:
0554: } else {
0555: longBufferForDecryption_ = new byte[count_
0556: - pos_ - firstLobLength];
0557: longPosForDecryption_ = 0;
0558: System.arraycopy(buffer_,
0559: pos_ + firstLobLength,
0560: longBufferForDecryption_, 0,
0561: longBufferForDecryption_.length);
0562:
0563: }
0564: } //end if(flag)
0565: int lobLength = ((clearedByte[0] & 0xFF) << 8)
0566: + ((clearedByte[1] & 0xFF) << 0) - 4;
0567:
0568: longValueForDecryption_ = new byte[lobLength];
0569:
0570: System.arraycopy(clearedByte, 4,
0571: longValueForDecryption_, 0,
0572: clearedByte.length - 4); //copy the decrypted lob value (excluded length an dcodepoint) to longValue_
0573: } else if (((clearedByte[2] & 0xff) << 8)
0574: + ((clearedByte[3] & 0xff) << 0) == 0x241B) {
0575: int length = ((clearedByte[0] & 0xFF) << 8)
0576: + ((clearedByte[1] & 0xFF) << 0);
0577: boolean noData = false;
0578: if (clearedByte[4] == -1 && clearedByte[5] == -1) {
0579: noData = true; //there is no data, no need to do the copy
0580: }
0581: if (!noData) {
0582: if (length == 32776) {
0583: length = ((clearedByte[4] & 0xFF) << 24)
0584: + ((clearedByte[5] & 0xFF) << 16)
0585: + ((clearedByte[6] & 0xFF) << 8)
0586: + ((clearedByte[7] & 0xFF) << 0);
0587: longValueForDecryption_ = new byte[length];
0588: System.arraycopy(clearedByte, 8,
0589: longValueForDecryption_, 0,
0590: clearedByte.length - 8);
0591: longCountForDecryption_ = count_
0592: - (pos_ + length + 8);
0593: longBufferForDecryption_ = new byte[buffer_.length
0594: - pos_ - length - 8];
0595: System.arraycopy(buffer_, pos_ + length + 8,
0596: longBufferForDecryption_, 0,
0597: longBufferForDecryption_.length);
0598:
0599: } else {
0600: longPosForDecryption_ = 0;
0601: longCountForDecryption_ = count_
0602: - (pos_ + length);
0603: longBufferForDecryption_ = new byte[buffer_.length
0604: - pos_ - length];
0605: System.arraycopy(buffer_, pos_ + length,
0606: longBufferForDecryption_, 0,
0607: longBufferForDecryption_.length);
0608:
0609: longValueForDecryption_ = new byte[length - 4];
0610:
0611: System.arraycopy(clearedByte, 4,
0612: longValueForDecryption_, 0,
0613: clearedByte.length - 4);
0614: }
0615: }
0616: }
0617: }
0618: }
0619:
0620: final int readUnsignedShort() throws DisconnectException {
0621: // should we be checking dss lengths and ddmScalarLengths here
0622: // if yes, i am not sure this is the correct place if we should be checking
0623: ensureBLayerDataInBuffer(2);
0624: adjustLengths(2);
0625: return ((buffer_[pos_++] & 0xff) << 8)
0626: + ((buffer_[pos_++] & 0xff) << 0);
0627: }
0628:
0629: final short readShort() throws DisconnectException {
0630: // should we be checking dss lengths and ddmScalarLengths here
0631: ensureBLayerDataInBuffer(2);
0632: adjustLengths(2);
0633: short s = SignedBinary.getShort(buffer_, pos_);
0634:
0635: pos_ += 2;
0636:
0637: return s;
0638: }
0639:
0640: final int readInt() throws DisconnectException {
0641: // should we be checking dss lengths and ddmScalarLengths here
0642: ensureBLayerDataInBuffer(4);
0643: adjustLengths(4);
0644: int i = SignedBinary.getInt(buffer_, pos_);
0645: pos_ += 4;
0646:
0647: return i;
0648: }
0649:
0650: final void readIntArray(int[] array) throws DisconnectException {
0651: ensureBLayerDataInBuffer(array.length * 4);
0652: adjustLengths(array.length * 4);
0653:
0654: for (int i = 0; i < array.length; i++) {
0655: array[i] = SignedBinary.getInt(buffer_, pos_);
0656: pos_ += 4;
0657: }
0658: }
0659:
0660: final long readLong() throws DisconnectException {
0661: // should we be checking dss lengths and ddmScalarLengths here
0662: ensureBLayerDataInBuffer(8);
0663: adjustLengths(8);
0664: long l = SignedBinary.getLong(buffer_, pos_);
0665:
0666: pos_ += 8;
0667:
0668: return l;
0669: }
0670:
0671: final int[] readUnsignedShortList() throws DisconnectException {
0672: int len = ddmScalarLen_;
0673: ensureBLayerDataInBuffer(len);
0674: adjustLengths(len);
0675:
0676: int count = len / 2;
0677: int[] list = new int[count];
0678:
0679: for (int i = 0; i < count; i++) {
0680: list[i] = ((buffer_[pos_++] & 0xff) << 8)
0681: + ((buffer_[pos_++] & 0xff) << 0);
0682: }
0683:
0684: return list;
0685: }
0686:
0687: final int readUnsignedByte() throws DisconnectException {
0688: ensureBLayerDataInBuffer(1);
0689: adjustLengths(1);
0690: return (buffer_[pos_++] & 0xff);
0691: }
0692:
0693: final byte readByte() throws DisconnectException {
0694: ensureBLayerDataInBuffer(1);
0695: adjustLengths(1);
0696: return (byte) (buffer_[pos_++] & 0xff);
0697: }
0698:
0699: final boolean readBoolean() throws DisconnectException {
0700: ensureBLayerDataInBuffer(1);
0701: adjustLengths(1);
0702: return buffer_[pos_++] != 0;
0703: }
0704:
0705: final String readString(int length) throws DisconnectException {
0706: ensureBLayerDataInBuffer(length);
0707: adjustLengths(length);
0708:
0709: String result = ccsidManager_.convertToUCS2(buffer_, pos_,
0710: length);
0711: pos_ += length;
0712: return result;
0713: }
0714:
0715: final String readString(int length, String encoding)
0716: throws DisconnectException {
0717: ensureBLayerDataInBuffer(length);
0718: adjustLengths(length);
0719: String s = null;
0720:
0721: try {
0722: s = new String(buffer_, pos_, length, encoding);
0723: } catch (java.io.UnsupportedEncodingException e) {
0724: agent_
0725: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
0726: agent_,
0727: new ClientMessageId(
0728: SQLState.NET_ENCODING_NOT_SUPPORTED),
0729: e));
0730: }
0731:
0732: pos_ += length;
0733: return s;
0734: }
0735:
0736: final String readString() throws DisconnectException {
0737: int len = ddmScalarLen_;
0738: ensureBLayerDataInBuffer(len);
0739: adjustLengths(len);
0740: String result = ccsidManager_.convertToUCS2(buffer_, pos_, len);
0741: pos_ += len;
0742: return result;
0743: }
0744:
0745: final byte[] readBytes(int length) throws DisconnectException {
0746: ensureBLayerDataInBuffer(length);
0747: adjustLengths(length);
0748:
0749: byte[] b = new byte[length];
0750: System.arraycopy(buffer_, pos_, b, 0, length);
0751: pos_ += length;
0752: return b;
0753: }
0754:
0755: final byte[] readBytes() throws DisconnectException {
0756: int len = ddmScalarLen_;
0757: ensureBLayerDataInBuffer(len);
0758: adjustLengths(len);
0759:
0760: byte[] b = new byte[len];
0761: System.arraycopy(buffer_, pos_, b, 0, len);
0762: pos_ += len;
0763: return b;
0764: }
0765:
0766: final byte[] readLDBytes() throws DisconnectException {
0767: ensureBLayerDataInBuffer(2);
0768: int len = ((buffer_[pos_++] & 0xff) << 8)
0769: + ((buffer_[pos_++] & 0xff) << 0);
0770:
0771: if (len == 0) {
0772: adjustLengths(2);
0773: return null;
0774: }
0775:
0776: ensureBLayerDataInBuffer(len);
0777: adjustLengths(len + 2);
0778:
0779: byte[] b = new byte[len];
0780: System.arraycopy(buffer_, pos_, b, 0, len);
0781: pos_ += len;
0782: return b;
0783: }
0784:
0785: final void skipBytes(int length) throws DisconnectException {
0786: ensureBLayerDataInBuffer(length);
0787: adjustLengths(length);
0788: pos_ += length;
0789: }
0790:
0791: final void skipBytes() throws DisconnectException {
0792: int len = ddmScalarLen_;
0793: ensureBLayerDataInBuffer(len);
0794: adjustLengths(len);
0795: pos_ += len;
0796: }
0797:
0798: // This will be the new and improved getData that handles all QRYDTA/EXTDTA
0799: // Returns the stream so that the caller can cache it
0800: final ByteArrayOutputStream getData(
0801: ByteArrayOutputStream existingBuffer)
0802: throws DisconnectException {
0803: boolean readHeader;
0804: int copySize;
0805: ByteArrayOutputStream baos;
0806:
0807: // note: an empty baos can yield an allocated and empty byte[]
0808: if (existingBuffer != null) {
0809: baos = existingBuffer;
0810: } else {
0811: if (ddmScalarLen_ != -1) {
0812: // allocate a stream based on a known amount of data
0813: baos = new ByteArrayOutputStream(ddmScalarLen_);
0814: } else {
0815: // allocate a stream to hold an unknown amount of data
0816: baos = new ByteArrayOutputStream();
0817: //isLengthAndNullabilityUnknown = true;
0818: }
0819: }
0820:
0821: // set the amount to read for the first segment
0822: copySize = dssLength_; // note: has already been adjusted for headers
0823:
0824: do {
0825: // determine if a continuation header needs to be read after the data
0826: if (dssIsContinued_) {
0827: readHeader = true;
0828: } else {
0829: readHeader = false;
0830: }
0831:
0832: // read the segment
0833: ensureALayerDataInBuffer(copySize);
0834: adjustLengths(copySize);
0835: baos.write(buffer_, pos_, copySize);
0836: pos_ += copySize;
0837:
0838: // read the continuation header, if necessary
0839: if (readHeader) {
0840: readDSSContinuationHeader();
0841: }
0842:
0843: copySize = dssLength_;
0844: } while (readHeader == true);
0845:
0846: return baos;
0847: }
0848:
0849: // reads a DSS continuation header
0850: // prereq: pos_ is positioned on the first byte of the two-byte header
0851: // post: dssIsContinued_ is set to true if the continuation bit is on, false otherwise
0852: // dssLength_ is set to DssConstants.MAX_DSS_LEN - 2 (don't count the header for the next read)
0853: // helper method for getEXTDTAData
0854: protected final void readDSSContinuationHeader()
0855: throws DisconnectException {
0856: ensureALayerDataInBuffer(2);
0857:
0858: dssLength_ = ((buffer_[pos_++] & 0xFF) << 8)
0859: + ((buffer_[pos_++] & 0xFF) << 0);
0860:
0861: if ((dssLength_ & 0x8000) == 0x8000) {
0862: dssLength_ = DssConstants.MAX_DSS_LEN;
0863: dssIsContinued_ = true;
0864: } else {
0865: dssIsContinued_ = false;
0866: }
0867: // it is a syntax error if the dss continuation header length
0868: // is less than or equal to two
0869: if (dssLength_ <= 2) {
0870: doSyntaxrmSemantics(CodePoint.SYNERRCD_DSS_CONT_LESS_OR_EQUAL_2);
0871: }
0872:
0873: dssLength_ -= 2; // avoid consuming the DSS cont header
0874: }
0875:
0876: // As part of parsing the reply, the client can detect that the
0877: // data sent from the target agent does not structurally
0878: // conform to the requirements of the DDM architecture. These are
0879: // the same checks performed by the target server on the messages
0880: // it receives from the protocolj code. Server side detected errors
0881: // result in a SYNTAXRM being returned from the AS. According to the
0882: // DDM manual, parsing of the DSS is terminated when the error is
0883: // detected. The Syntax Error Code, SYNERRCD, describes the various errors.
0884: //
0885: // Note: Not all of these may be valid at the client. See descriptions for
0886: // which ones make sense for client side errors/checks.
0887: // Syntax Error Code Description of Error
0888: // ----------------- --------------------
0889: // 0x01 Dss header Length is less than 6.
0890: // 0x02 Dss header Length does not match the
0891: // number of bytes of data found.
0892: // 0x03 Dss header C-byte not D0.
0893: // 0x04 Dss header f-bytes either not
0894: // recognized or not supported.
0895: // 0x05 DSS continuation specified but not found.
0896: // For example, DSS continuation is specified
0897: // on the last DSS, and the SNA LU 6.2 communication
0898: // facility returned the SEND indicator.
0899: // 0x06 DSS chaining specified but no DSS found.
0900: // For example, DSS chaining is specified
0901: // on the last DSS, and the SNA LU 6.2 communication
0902: // facility returned the SEND indicator.
0903: // 0x07 Object length less than four. For example,
0904: // a command parameter's length is specified
0905: // as two, or a command's length is specified as three.
0906: // 0x08 Object length does not match the number of bytes of data
0907: // found. For example, a RQSDSS with a length of 150
0908: // contains a command whose length is 125 or a SRVDGN parameter
0909: // specifies a length of 200 but there are only 50
0910: // bytes left in the DSS.
0911: // 0x09 Object length greater than maximum allowed.
0912: // For example, a RECCNT parameter specifies a
0913: // length of ten, but the parameter is defined
0914: // to have a maximum length of eight.
0915: // 0x0A Object length less than the minimum required.
0916: // For example, a SVRCOD parameter specifies a
0917: // length of five, but the parameter is defined
0918: // to have a fixed length of six.
0919: // 0x0B Object length not allowed. For example,
0920: // a FILEXDPT parameter is specified with a length of
0921: // 11, but this would indicate that only half of the hours
0922: // field is present instead of the complete hours field.
0923: // 0x0C Incorrect large object extended length field (see
0924: // description of DSS). For example, an extended
0925: // length field is present, but it is only three bytes
0926: // long when it is defined to be a multiple of two bytes.
0927: // 0x0D Object code point index not supported.
0928: // For example, a code point of 8032 is encountered
0929: // but x'8' is a reserved code point index.
0930: // 0x0E Required object not found. For example, a CLEAR
0931: // command does not have a filnam parameter present,
0932: // or a MODREC command is not followed by a RECORD
0933: // command data object.
0934: // 0x0F Too many command data objects sent. For example,
0935: // a MODREC command is followed by two RECORD command
0936: // command data objects, or a DECREC command is followed
0937: // by RECORD object.
0938: // 0x10 Mutually exclusive objects present.
0939: // For example, a CRTDIRF command specifies both
0940: // a DCLNAM and FILNAM parameters.
0941: // 0x11 Too few command data objects sent.
0942: // For example, an INSRECEF command that
0943: // specified RECCNT95) is followed by only
0944: // 4 RECORD command data objects.
0945: // 0x12 Duplicate object present.
0946: // For example, a LSTFAT command has tow FILNAM
0947: // parameters specified.
0948: // 0x13 Invalid request correlator specified.
0949: // Use PRCCNVRM with PRCCNVDC of 04 or 05 instead
0950: // of this error code. This error code is being retained
0951: // for compatibility with Level 1 of the architecture.
0952: // 0x14 Required value not found.
0953: // 0x15 Reserved value not allowed. For example,
0954: // a INSRECEF command specified a RECCNT(0) parameter.
0955: // 0x16 DSS continuation less than or equal to two.
0956: // For example, the length bytes of the DSS continuation
0957: // have the value of one.
0958: // 0x17 Objects not in required order. For example, a RECAL
0959: // object contains a RECORD object followed by a RECNBR
0960: // object with is not in the defined order.
0961: // 0x18 DSS chaining byt not b'1', but DSSFMT bit3 set to b'1'.
0962: // 0x19 Previous DSS indicated current DSS has the same
0963: // request correlator, but the request correlators are
0964: // not the same.
0965: // 0x1A DSS cahining bit not b'1', but error continuation requested.
0966: // 0x1B Mutually exclusive parameter values not specified.
0967: // For example, an OPEN command specified PRPSHD(TRUE)
0968: // and FILSHR(READER).
0969: // 0x1D Code point not valid command. For example, the first
0970: // code point in RQSDSS either is not in the dictionary
0971: // or is not a code point for a command.
0972: //
0973: // When the client detects these errors, it will be handled as if a SYNTAXRM is returned
0974: // from the server. In this SYNTAXRM case, PROTOCOL architects an SQLSTATE of 58008 or 58009.
0975: //
0976: // Messages
0977: // SQLSTATE : 58009
0978: // Execution failed due to a distribution protocol error that caused deallocation of the conversation.
0979: // SQLCODE : -30020
0980: // Execution failed because of a Distributed Protocol
0981: // Error that will affect the successful execution of subsequent
0982: // commands and SQL statements: Reason Code <reason-code>.
0983: // Some possible reason codes include:
0984: // 121C Indicates that the user is not authorized to perform the requested command.
0985: // 1232 The command could not be completed because of a permanent error.
0986: // In most cases, the server will be in the process of an abend.
0987: // 220A The target server has received an invalid data description.
0988: // If a user SQLDA is specified, ensure that the fields are
0989: // initialized correctly. Also, ensure that the length does not
0990: // exceed the maximum allowed length for the data type being used.
0991: //
0992: // The command or statement cannot be processed. The current
0993: // transaction is rolled back and the application is disconnected
0994: // from the remote database.
0995: final void doSyntaxrmSemantics(int syntaxErrorCode)
0996: throws DisconnectException {
0997: agent_
0998: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
0999: agent_,
1000: new ClientMessageId(
1001: SQLState.DRDA_CONNECTION_TERMINATED),
1002: SqlException
1003: .getMessageUtil()
1004: .getTextMessage(
1005: MessageId.CONN_DRDA_DATASTREAM_SYNTAX_ERROR,
1006: new Integer(syntaxErrorCode))));
1007: }
1008:
1009: // the names of these methods start with a letter z.
1010: // the z will be removed when they are finalized...
1011:
1012: protected final void pushLengthOnCollectionStack() {
1013: ddmCollectionLenStack_[++topDdmCollectionStack_] = ddmScalarLen_;
1014: ddmScalarLen_ = 0;
1015: }
1016:
1017: protected final void adjustLengths(int length) {
1018: ddmScalarLen_ -= length;
1019: adjustCollectionAndDssLengths(length);
1020: /*
1021: for (int i = 0; i <= topDdmCollectionStack_; i++) {
1022: ddmCollectionLenStack_[i] -= length;
1023: }
1024: dssLength_ -= length;
1025: */
1026: }
1027:
1028: protected int adjustDdmLength(int ddmLength, int length) {
1029: ddmLength -= length;
1030: if (ddmLength == 0) {
1031: adjustLengths(getDdmLength());
1032: }
1033: return ddmLength;
1034: }
1035:
1036: // Pop the collection Length stack.
1037: // pre: The collection length stack must not be empty and the top value
1038: // on the stack must be 0.
1039: // post: The top 0 value on the stack will be popped.
1040: protected final void popCollectionStack() {
1041: topDdmCollectionStack_--;
1042: }
1043:
1044: protected final int peekCodePoint() throws DisconnectException {
1045: if (topDdmCollectionStack_ != EMPTY_STACK) {
1046: if (ddmCollectionLenStack_[topDdmCollectionStack_] == 0) {
1047: return END_OF_COLLECTION;
1048: } else if (ddmCollectionLenStack_[topDdmCollectionStack_] < 4) {
1049: // error
1050: }
1051: }
1052:
1053: // if there is no more data in the current dss, and the dss is not
1054: // continued, indicate the end of the same Id chain or read the next dss header.
1055: if ((dssLength_ == 0) && (!dssIsContinued_)) {
1056: if (!dssIsChainedWithSameID_) {
1057: return END_OF_SAME_ID_CHAIN;
1058: }
1059: readDssHeader();
1060: }
1061:
1062: if (longBufferForDecryption_ == null) //we don't need to do this if it's data stream encryption
1063: {
1064: ensureBLayerDataInBuffer(4);
1065: }
1066: peekedLength_ = ((buffer_[pos_] & 0xff) << 8)
1067: + ((buffer_[pos_ + 1] & 0xff) << 0);
1068: peekedCodePoint_ = ((buffer_[pos_ + 2] & 0xff) << 8)
1069: + ((buffer_[pos_ + 3] & 0xff) << 0);
1070:
1071: // check for extended length
1072: if ((peekedLength_ & 0x8000) == 0x8000) {
1073: peekExtendedLength();
1074: } else {
1075: peekedNumOfExtendedLenBytes_ = 0;
1076: }
1077: return peekedCodePoint_;
1078: }
1079:
1080: // Read out the 2-byte length without moving the pos_ pointer.
1081: protected final int peekLength() throws DisconnectException {
1082: ensureBLayerDataInBuffer(2);
1083: return (((buffer_[pos_] & 0xff) << 8) + ((buffer_[pos_ + 1] & 0xff) << 0));
1084: }
1085:
1086: // Read "length" number of bytes from the buffer into the byte array b starting from offset
1087: // "offset". The current offset in the buffer does not change.
1088: protected final int peekFastBytes(byte[] b, int offset, int length)
1089: throws DisconnectException {
1090: for (int i = 0; i < length; i++) {
1091: b[offset + i] = buffer_[pos_ + i];
1092: }
1093: return offset + length;
1094: }
1095:
1096: protected final void parseLengthAndMatchCodePoint(
1097: int expectedCodePoint) throws DisconnectException {
1098: int actualCodePoint = 0;
1099: if (peekedCodePoint_ == END_OF_COLLECTION) {
1100: actualCodePoint = readLengthAndCodePoint();
1101: } else {
1102: actualCodePoint = peekedCodePoint_;
1103: pos_ += (4 + peekedNumOfExtendedLenBytes_);
1104: ddmScalarLen_ = peekedLength_;
1105: if (peekedNumOfExtendedLenBytes_ == 0
1106: && ddmScalarLen_ != -1) {
1107: adjustLengths(4);
1108: } else {
1109: adjustCollectionAndDssLengths(4 + peekedNumOfExtendedLenBytes_);
1110: }
1111: peekedLength_ = 0;
1112: peekedCodePoint_ = END_OF_COLLECTION;
1113: peekedNumOfExtendedLenBytes_ = 0;
1114: }
1115:
1116: if (actualCodePoint != expectedCodePoint) {
1117: agent_
1118: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
1119: agent_,
1120: new ClientMessageId(
1121: SQLState.NET_NOT_EXPECTED_CODEPOINT),
1122: new Integer(actualCodePoint), new Integer(
1123: expectedCodePoint)));
1124: }
1125: }
1126:
1127: protected final int readLengthAndCodePoint()
1128: throws DisconnectException {
1129: if (topDdmCollectionStack_ != EMPTY_STACK) {
1130: if (ddmCollectionLenStack_[topDdmCollectionStack_] == 0) {
1131: return END_OF_COLLECTION;
1132: } else if (ddmCollectionLenStack_[topDdmCollectionStack_] < 4) {
1133: agent_
1134: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
1135: agent_,
1136: new ClientMessageId(
1137: SQLState.NET_DDM_COLLECTION_TOO_SMALL)));
1138: }
1139: }
1140:
1141: // if there is no more data in the current dss, and the dss is not
1142: // continued, indicate the end of the same Id chain or read the next dss header.
1143: if ((dssLength_ == 0) && (!dssIsContinued_)) {
1144: if (!dssIsChainedWithSameID_) {
1145: return END_OF_SAME_ID_CHAIN;
1146: }
1147: readDssHeader();
1148: }
1149:
1150: ensureBLayerDataInBuffer(4);
1151: ddmScalarLen_ = ((buffer_[pos_++] & 0xff) << 8)
1152: + ((buffer_[pos_++] & 0xff) << 0);
1153: int codePoint = ((buffer_[pos_++] & 0xff) << 8)
1154: + ((buffer_[pos_++] & 0xff) << 0);
1155: adjustLengths(4);
1156:
1157: // check for extended length
1158: if ((ddmScalarLen_ & 0x8000) == 0x8000) {
1159: readExtendedLength();
1160: }
1161: return codePoint;
1162: }
1163:
1164: private final void readExtendedLength() throws DisconnectException {
1165: int numberOfExtendedLenBytes = (ddmScalarLen_ - 0x8000); // fix scroll problem was - 4
1166: int adjustSize = 0;
1167: switch (numberOfExtendedLenBytes) {
1168: case 4:
1169: ensureBLayerDataInBuffer(4);
1170: ddmScalarLen_ = ((buffer_[pos_++] & 0xff) << 24)
1171: + ((buffer_[pos_++] & 0xff) << 16)
1172: + ((buffer_[pos_++] & 0xff) << 8)
1173: + ((buffer_[pos_++] & 0xff) << 0);
1174: adjustSize = 4;
1175: break;
1176: case 0:
1177: ddmScalarLen_ = -1;
1178: adjustSize = 0;
1179: break;
1180: default:
1181: doSyntaxrmSemantics(CodePoint.SYNERRCD_INCORRECT_EXTENDED_LEN);
1182: }
1183:
1184: adjustCollectionAndDssLengths(adjustSize);
1185: /*
1186: // adjust the lengths here. this is a special case since the
1187: // extended length bytes do not include their own length.
1188: for (int i = 0; i <= topDdmCollectionStack_; i++) {
1189: ddmCollectionLenStack_[i] -= adjustSize;
1190: }
1191: dssLength_ -= adjustSize;
1192: */
1193: }
1194:
1195: private final void adjustCollectionAndDssLengths(int length) {
1196: // adjust the lengths here. this is a special case since the
1197: // extended length bytes do not include their own length.
1198: for (int i = 0; i <= topDdmCollectionStack_; i++) {
1199: ddmCollectionLenStack_[i] -= length;
1200: }
1201: dssLength_ -= length;
1202: }
1203:
1204: protected final void startSameIdChainParse()
1205: throws DisconnectException {
1206: readDssHeader();
1207: netAgent_.clearSvrcod();
1208: }
1209:
1210: protected final void endOfSameIdChainData()
1211: throws DisconnectException {
1212: netAgent_.targetTypdef_ = netAgent_.originalTargetTypdef_;
1213: netAgent_.targetSqlam_ = netAgent_.orignalTargetSqlam_;
1214:
1215: if (this .topDdmCollectionStack_ != Reply.EMPTY_STACK) {
1216: agent_
1217: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
1218: agent_,
1219: new ClientMessageId(
1220: SQLState.NET_COLLECTION_STACK_NOT_EMPTY)));
1221: }
1222: if (this .dssLength_ != 0) {
1223: agent_
1224: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
1225: agent_, new ClientMessageId(
1226: SQLState.NET_DSS_NOT_ZERO)));
1227: }
1228: if (dssIsChainedWithSameID_ == true) {
1229: agent_
1230: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
1231: agent_,
1232: new ClientMessageId(
1233: SQLState.NET_DSS_CHAINED_WITH_SAME_ID)));
1234: }
1235: }
1236:
1237: protected final int peekTotalColumnCount(int tripletLength)
1238: throws DisconnectException {
1239: int columnCount = 0;
1240: int offset = 0;
1241: int tripletType = FdocaConstants.CPT_TRIPLET_TYPE;
1242: while (tripletType == FdocaConstants.CPT_TRIPLET_TYPE) {
1243: columnCount += ((tripletLength - 3) / 3);
1244: // Peek ahead for the next triplet's tripletLength and tripletType.
1245: // The number of bytes to skip before the next tripletType is tripletLength - 3.
1246: ensureBLayerDataInBuffer(tripletLength - 3);
1247: offset += (tripletLength - 3);
1248: tripletLength = (buffer_[pos_ + offset++] & 0xff);
1249: tripletType = (buffer_[pos_ + offset++] & 0xff);
1250: // Skip the 1-byte tripletId.
1251: offset++;
1252: }
1253: return columnCount;
1254: }
1255:
1256: private final void peekExtendedLength() throws DisconnectException {
1257: peekedNumOfExtendedLenBytes_ = (peekedLength_ - 0x8004);
1258: switch (peekedNumOfExtendedLenBytes_) {
1259: case 4:
1260: // L L C P Extended Length
1261: // -->2-bytes<-- --->4-bytes<---
1262: // We are only peeking the length here, the actual pos_ is still before LLCP. We ensured
1263: // 4-bytes in peedCodePoint() for the LLCP, and we need to ensure 4-bytes(of LLCP) + the
1264: // extended length bytes here.
1265: if (longBufferForDecryption_ == null) //we ddon't need to do this if it's data stream encryption
1266: {
1267: ensureBLayerDataInBuffer(4 + 4);
1268: }
1269: // The ddmScalarLen_ we peek here does not include the LLCP and the extended length bytes
1270: // themselves. So we will add those back to the ddmScalarLen_ so it can be adjusted
1271: // correctly in parseLengthAndMatchCodePoint(). (since the adjustLengths() method will
1272: // subtract the length from ddmScalarLen_)
1273: peekedLength_ = ((buffer_[pos_ + 4] & 0xff) << 24)
1274: + ((buffer_[pos_ + 5] & 0xff) << 16)
1275: + ((buffer_[pos_ + 6] & 0xff) << 8)
1276: + ((buffer_[pos_ + 7] & 0xff) << 0);
1277: break;
1278: case 0:
1279: peekedLength_ = -1; // this ddm is streamed, so set -1 -> length unknown
1280: break;
1281: default:
1282: doSyntaxrmSemantics(CodePoint.SYNERRCD_INCORRECT_EXTENDED_LEN);
1283: }
1284: }
1285:
1286: final int readFastUnsignedByte() throws DisconnectException {
1287: return (buffer_[pos_++] & 0xff);
1288: }
1289:
1290: final short readFastShort() throws DisconnectException {
1291: short s = SignedBinary.getShort(buffer_, pos_);
1292: pos_ += 2;
1293: return s;
1294: }
1295:
1296: final int readFastUnsignedShort() throws DisconnectException {
1297: return ((buffer_[pos_++] & 0xff) << 8)
1298: + ((buffer_[pos_++] & 0xff) << 0);
1299: }
1300:
1301: final int readFastInt() throws DisconnectException {
1302: int i = SignedBinary.getInt(buffer_, pos_);
1303: pos_ += 4;
1304: return i;
1305: }
1306:
1307: final String readFastString(int length) throws DisconnectException {
1308: String result = ccsidManager_.convertToUCS2(buffer_, pos_,
1309: length);
1310: pos_ += length;
1311: return result;
1312: }
1313:
1314: final byte[] readFastBytes(int length) throws DisconnectException {
1315: byte[] b = new byte[length];
1316: System.arraycopy(buffer_, pos_, b, 0, length);
1317: pos_ += length;
1318: return b;
1319: }
1320:
1321: protected final int peekFastLength() throws DisconnectException {
1322: return (((buffer_[pos_] & 0xff) << 8) + ((buffer_[pos_ + 1] & 0xff) << 0));
1323: }
1324:
1325: final void skipFastBytes(int length) throws DisconnectException {
1326: pos_ += length;
1327: }
1328:
1329: final void readFastIntArray(int[] array) throws DisconnectException {
1330: for (int i = 0; i < array.length; i++) {
1331: array[i] = SignedBinary.getInt(buffer_, pos_);
1332: pos_ += 4;
1333: }
1334: }
1335:
1336: final String readFastString(int length, String encoding)
1337: throws DisconnectException {
1338: String s = null;
1339:
1340: try {
1341: s = new String(buffer_, pos_, length, encoding);
1342: } catch (java.io.UnsupportedEncodingException e) {
1343: agent_
1344: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
1345: agent_,
1346: new ClientMessageId(
1347: SQLState.NET_ENCODING_NOT_SUPPORTED),
1348: e));
1349: }
1350: pos_ += length;
1351: return s;
1352: }
1353:
1354: final byte[] readFastLDBytes() throws DisconnectException {
1355: int len = ((buffer_[pos_++] & 0xff) << 8)
1356: + ((buffer_[pos_++] & 0xff) << 0);
1357: if (len == 0) {
1358: return null;
1359: }
1360:
1361: byte[] b = new byte[len];
1362: System.arraycopy(buffer_, pos_, b, 0, len);
1363: pos_ += len;
1364: return b;
1365: }
1366:
1367: final long readFastLong() throws DisconnectException {
1368: long l = SignedBinary.getLong(buffer_, pos_);
1369: pos_ += 8;
1370: return l;
1371: }
1372:
1373: final byte readFastByte() throws DisconnectException {
1374: return (byte) (buffer_[pos_++] & 0xff);
1375: }
1376:
1377: final void mark() {
1378: currentPos_ = pos_;
1379: }
1380:
1381: // remove and return the top offset value from mark stack.
1382: final int popMark() {
1383: return currentPos_;
1384: }
1385:
1386: final int getFastSkipSQLCARDrowLength() {
1387: return pos_ - popMark();
1388: }
1389:
1390: // The only difference between this method and the original getData() method is this method
1391: // is not doing an ensureALayerDataInBuffer
1392: final ByteArrayOutputStream getFastData(
1393: ByteArrayOutputStream existingBuffer)
1394: throws DisconnectException {
1395: boolean readHeader;
1396: int copySize;
1397: ByteArrayOutputStream baos;
1398:
1399: // note: an empty baos can yield an allocated and empty byte[]
1400: if (existingBuffer != null) {
1401: baos = existingBuffer;
1402: } else {
1403: if (ddmScalarLen_ != -1) {
1404: // allocate a stream based on a known amount of data
1405: baos = new ByteArrayOutputStream(ddmScalarLen_);
1406: } else {
1407: // allocate a stream to hold an unknown amount of data
1408: baos = new ByteArrayOutputStream();
1409: //isLengthAndNullabilityUnknown = true;
1410: }
1411: }
1412:
1413: // set the amount to read for the first segment
1414: copySize = dssLength_; // note: has already been adjusted for headers
1415:
1416: do {
1417: // determine if a continuation header needs to be read after the data
1418: if (dssIsContinued_) {
1419: readHeader = true;
1420: } else {
1421: readHeader = false;
1422: }
1423:
1424: // read the segment
1425: //ensureALayerDataInBuffer (copySize);
1426: adjustLengths(copySize);
1427: baos.write(buffer_, pos_, copySize);
1428: pos_ += copySize;
1429:
1430: // read the continuation header, if necessary
1431: if (readHeader) {
1432: readDSSContinuationHeader();
1433: }
1434:
1435: copySize = dssLength_;
1436: } while (readHeader == true);
1437:
1438: return baos;
1439: }
1440:
1441: // This method is only used to match the codePoint for those class instance variables
1442: // that are embedded in other reply messages.
1443: final protected void matchCodePoint(int expectedCodePoint)
1444: throws DisconnectException {
1445: int actualCodePoint = 0;
1446: actualCodePoint = peekedCodePoint_;
1447: pos_ += 4;
1448: if (actualCodePoint != expectedCodePoint) {
1449: agent_
1450: .accumulateChainBreakingReadExceptionAndThrow(new DisconnectException(
1451: agent_,
1452: new ClientMessageId(
1453: SQLState.NET_NOT_EXPECTED_CODEPOINT),
1454: new Integer(actualCodePoint), new Integer(
1455: expectedCodePoint)));
1456: }
1457: }
1458:
1459: protected final int peekNumOfColumns() throws DisconnectException {
1460: // skip the 4-byte LLCP and any extended length bytes + 1-byte null sqlcagrp null indicator
1461: int offset = (4 + peekedNumOfExtendedLenBytes_ + 1);
1462:
1463: offset = skipSQLDHROW(offset);
1464:
1465: return SignedBinary.getShort(buffer_, pos_ + offset);
1466: }
1467:
1468: protected final boolean peekForNullSqlcagrp() {
1469: // skip the 4-byte LLCP and any extended length bytes
1470: int offset = (4 + peekedNumOfExtendedLenBytes_);
1471: int nullInd = buffer_[pos_ + offset] & 0xff;
1472: return (nullInd == CodePoint.NULLDATA);
1473: }
1474:
1475: private final int skipSQLDHROW(int offset)
1476: throws DisconnectException {
1477: int sqldhrowgrpNullInd = buffer_[pos_ + offset++] & 0xff;
1478: if (sqldhrowgrpNullInd == CodePoint.NULLDATA) {
1479: return offset;
1480: }
1481:
1482: offset += 12;
1483:
1484: // skip sqldrdbnam
1485: int stringLength = ((buffer_[pos_ + offset++] & 0xff) << 8)
1486: + ((buffer_[pos_ + offset++] & 0xff) << 0);
1487: offset += stringLength;
1488:
1489: // skip sqldschema
1490: stringLength = ((buffer_[pos_ + offset++] & 0xff) << 8)
1491: + ((buffer_[pos_ + offset++] & 0xff) << 0);
1492: offset += stringLength;
1493:
1494: stringLength = ((buffer_[pos_ + offset++] & 0xff) << 8)
1495: + ((buffer_[pos_ + offset++] & 0xff) << 0);
1496: offset += stringLength;
1497:
1498: return offset;
1499: }
1500: }
|