docs: private int copyDataToCallerBuffers() {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.entry(tc, "copyDataToCallerBuffers");
          }
          WsByteBuffer src[] = decryptedNetBuffers;
          WsByteBuffer dst[] = getBuffers();
          WsByteBuffer dstBuffer = null;
          WsByteBuffer srcBuffer = null;
          int dstIndex = 0;
          int srcIndex = 0;
          int srcRemaining = 0;
          int dstRemaining = 0;
          int numBytesCopied = 0;
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "Before copy:\r\n\tsrc: " + SSLUtils.getBufferTraceInfo(src)
                           + "\r\n\tdst: " + SSLUtils.getBufferTraceInfo(dst));
          }
  
          // Loop through the destination array.
          for (; srcIndex < src.length && dstIndex < dst.length; srcIndex++) {
              // Access the next src buffer
              srcBuffer = src[srcIndex];
              srcRemaining = srcBuffer.remaining();
              while (srcRemaining > 0 && dstIndex < dst.length) {
                  // Access the current dst buffer.
                  dstBuffer = dst[dstIndex];
                  dstRemaining = dstBuffer.remaining();
                  // Data available in src buffer to be copied.
                  if (srcRemaining <= dstRemaining) {
                      // All data in src will fit in dst, but room may still be left in dst.
                      SSLUtils.copyBuffer(srcBuffer, dstBuffer, srcRemaining);
                      numBytesCopied += srcRemaining;
                      // Check if any room left in dst.
                      dstRemaining = dstBuffer.remaining();
                      if (dstRemaining == 0) {
                          // No more room in dst buffer. Shift dst array index.
                          dstIndex++;
                      }
                      break;
                  } else if (dstRemaining > 0) {
                      // Dst is smaller than src, but there is some room.
                      SSLUtils.copyBuffer(srcBuffer, dstBuffer, dstRemaining);
                      numBytesCopied += dstRemaining;
                      // No more room in dst buffer. Shift dst array index.
                      dstIndex++;
                      // Update data left in src buffer.
                      srcRemaining = srcBuffer.remaining();
                      continue;
                  } else {
                      // current destination buffer is completely full already
                      dstIndex++;
                  }
              }
          }
          // decrement source array index back to the last one used
          srcIndex--;
  
          // At this point, the dst buffer has been filled as much as possible.
          // Now we have to look for left over data in the src buffer to save
          // for a future read request. Note that the src buffer may actually
          // be unconsumedDecData.
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "After copy:\r\n\tsrc: " + SSLUtils.getBufferTraceInfo(src)
                           + "\r\n\tdst: " + SSLUtils.getBufferTraceInfo(dst));
          }
  
          // figure out how much remaining decrypted data is available
          int remaining = SSLUtils.lengthOf(src, srcIndex);
  
          // Check if the src is the unconsumedDecData
          if (src == unconsumedDecData && null != srcBuffer
              && (srcBuffer.hashCode() == unconsumedDecData[srcIndex].hashCode())) {
              // Check if all the data was drained from the unconsumedDecData buffer.
              if (0 < remaining) {
                  // Data is left in the unconsumedDecData buffer. Need to shift
                  // it to position 0 for a future read.
                  WsByteBuffer temp = unconsumedDecData[srcIndex];
                  unconsumedDecData[srcIndex] = unconsumedDecData[srcIndex].slice();
                  temp.release();
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Data left in unconsumedDecData: "
                                   + SSLUtils.getBufferTraceInfo(unconsumedDecData));
                  }
              } else {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Entire unconsumedDecData buffer drained.  Release and null out.");
                  }
                  // Data was completely drained.
                  WsByteBufferUtils.releaseBufferArray(unconsumedDecData);
                  unconsumedDecData = null;
              }
  
              // otherwise copy anything that's left
          } else {
              if (0 < remaining) {
                  unconsumedDecData = SSLUtils.compressBuffers(decryptedNetBuffers, true);
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "unconsumedDecData: " + SSLUtils.getBufferTraceInfo(unconsumedDecData));
                  }
              } else {
                  cleanupDecBuffers();
              }
          }
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) {
              Tr.exit(tc, "copyDataToCallerBuffers: " + numBytesCopied);
          }
          return numBytesCopied;
      }