private CompletableFuture<S7Message> performVarLengthStringReadRequest(DefaultPlcReadRequest request) {
        CompletableFuture<S7Message> future = new CompletableFuture<>();

        // Replace the var-length string fields with requests to read the
        // length information instead of the string content.
        int numVarLengthStrings = 0;
        LinkedHashMap<String, PlcTagItem<PlcTag>> updatedRequestItems = new LinkedHashMap<>(request.getNumberOfTags());
        for (String tagName : request.getTagNames()) {
            PlcTagItem<PlcTag> plcTagItem = request.getTagItem(tagName);
            if(plcTagItem.getTag() instanceof S7StringVarLengthTag) {
                S7Tag s7Tag = (S7Tag) plcTagItem.getTag();
                TransportSize dataType = s7Tag.getDataType();
                if(dataType == TransportSize.STRING) {
                    updatedRequestItems.put(tagName, new DefaultPlcTagItem<>(new S7Tag(TransportSize.BYTE, s7Tag.getMemoryArea(), s7Tag.getBlockNumber(), s7Tag.getByteOffset(), s7Tag.getBitOffset(), 2)));
                    numVarLengthStrings++;
                } else if(dataType == TransportSize.WSTRING) {
                    updatedRequestItems.put(tagName, new DefaultPlcTagItem<>(new S7Tag(TransportSize.BYTE, s7Tag.getMemoryArea(), s7Tag.getBlockNumber(), s7Tag.getByteOffset(), s7Tag.getBitOffset(), 4)));
                    numVarLengthStrings++;
                }
            } else {
                updatedRequestItems.put(tagName, plcTagItem);
            }
        }

        CompletableFuture<S7Message> s7MessageCompletableFuture = performOrdinaryReadRequest(new DefaultPlcReadRequest(request.getReader(), updatedRequestItems));
        int finalNumVarLengthStrings = numVarLengthStrings;
        s7MessageCompletableFuture.whenComplete((s7Message, throwable1) -> {
            if (throwable1 != null) {
                future.completeExceptionally(throwable1);
                return;
            }
            // Collect the responses for the var-length strings and read them separately.
            LinkedHashMap<String, PlcTagItem<PlcTag>> varLengthStringTags = new LinkedHashMap<>(finalNumVarLengthStrings);
            int curItem = 0;
            for (String tagName : request.getTagNames()) {
                S7Tag s7tag = (S7Tag) request.getTag(tagName);
                if(s7tag instanceof S7StringVarLengthTag) {
                    S7VarPayloadDataItem s7VarPayloadDataItem = ((S7PayloadReadVarResponse) s7Message.getPayload()).getItems().get(curItem);
                    // Simply ignore processing var-length strings that are not ok
                    if(s7VarPayloadDataItem.getReturnCode() == DataTransportErrorCode.OK) {
                        ReadBuffer rb = new ReadBufferByteBased(s7VarPayloadDataItem.getData());
                        try {
                            if (s7tag.getDataType() == TransportSize.STRING) {
                                rb.readShort(8);
                                int stringLength = rb.readShort(8);
                                varLengthStringTags.put(tagName, new DefaultPlcTagItem<>(new S7StringFixedLengthTag(TransportSize.STRING, s7tag.getMemoryArea(), s7tag.getBlockNumber(), s7tag.getByteOffset(), s7tag.getBitOffset(), 1, stringLength)));
                            } else if (s7tag.getDataType() == TransportSize.WSTRING) {
                                rb.readInt(16);
                                int stringLength = rb.readInt(16);
                                varLengthStringTags.put(tagName, new DefaultPlcTagItem<>(new S7StringFixedLengthTag(TransportSize.WSTRING, s7tag.getMemoryArea(), s7tag.getBlockNumber(), s7tag.getByteOffset(), s7tag.getBitOffset(), 1, stringLength)));
                            }
                        } catch (Exception e) {
                            logger.warn("Error parsing string size for tag {}", tagName, e);
                        }
                    }
                }
                curItem++;
            }
            // TODO: Technically we would need to let this go through the optimizer in order to split things up.
            //  For this we need access to the PlcReader instance of this driver
            CompletableFuture<S7Message> readStringsCompletableFuture = performOrdinaryReadRequest(new DefaultPlcReadRequest(request.getReader(), varLengthStringTags));
            readStringsCompletableFuture.whenComplete((s7StringMessage, throwable2) -> {
                // Build a new S7Message that replaces the var-length string items of the previous request with the responses of this response.
                int curInitialItem = 0;
                int curVarLengthStringItem = 0;
                List<S7VarPayloadDataItem> varLengthStringItems = new ArrayList<>(request.getNumberOfTags());
                for (String tagName : request.getTagNames()) {
                    S7Tag s7tag = (S7Tag) request.getTag(tagName);
                    S7VarPayloadDataItem curResultItem = ((S7PayloadReadVarResponse) s7Message.getPayload()).getItems().get(curInitialItem);
                    if(s7tag instanceof S7StringVarLengthTag) {
                        if(curResultItem.getReturnCode() == DataTransportErrorCode.OK) {
                            curResultItem = ((S7PayloadReadVarResponse) s7StringMessage.getPayload()).getItems().get(curVarLengthStringItem);
                            curVarLengthStringItem++;
                        }
                    }
                    varLengthStringItems.add(curResultItem);
                    curInitialItem++;
                }
                future.complete(new S7MessageResponse(s7Message.getTpduReference(), s7Message.getParameter(), new S7PayloadReadVarResponse(varLengthStringItems), (short) 0, (short) 0));
            });
        });
        return future;
    }
Maps the S7ReadResponse of a PlcReadRequest to a PlcReadResponse
plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java