STATUS parseFragmentAck()

in src/client/src/AckParser.c [31:265]


STATUS parseFragmentAck(PKinesisVideoStream pKinesisVideoStream, UPLOAD_HANDLE uploadHandle, PCHAR ackSegment, UINT32 ackSegmentSize)
{
    ENTERS();
    STATUS retStatus = STATUS_SUCCESS;
    UINT32 index = 0;
    UINT32 level = 0;
    CHAR curChar;
    PKinesisVideoClient pKinesisVideoClient = NULL;
    BOOL streamLocked = FALSE;

    CHK(pKinesisVideoStream != NULL && ackSegment != NULL, STATUS_NULL_ARG);

    // If ack segment is specified and ack segment size is 0 then we should get the C-string size
    if (0 == ackSegmentSize) {
        ackSegmentSize = (UINT32) STRNLEN(ackSegment, MAX_ACK_FRAGMENT_LEN);
    } else {
        CHK(ackSegmentSize <= MAX_ACK_FRAGMENT_LEN, STATUS_INVALID_ACK_SEGMENT_LEN);
    }

    pKinesisVideoClient = pKinesisVideoStream->pKinesisVideoClient;
    pKinesisVideoClient->clientCallbacks.lockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoStream->base.lock);
    streamLocked = TRUE;

    // Set the upload handle
    if (!IS_VALID_UPLOAD_HANDLE(pKinesisVideoStream->fragmentAckParser.uploadHandle)) {
        pKinesisVideoStream->fragmentAckParser.uploadHandle = uploadHandle;
    }

    for (index = 0; index < ackSegmentSize; index++) {
        curChar = ackSegment[index];

        switch (pKinesisVideoStream->fragmentAckParser.state) {
            case FRAGMENT_ACK_PARSER_STATE_START:
                // Skip until the start of the segment
                if (ACK_PARSER_OPEN_BRACE == curChar) {
                    // Move to segment start state
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_ACK_START;
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_ACK_START:
                // Skip until non-whitespace
                if (!IS_WHITE_SPACE(curChar)) {
                    // We should have a quote
                    CHK(curChar == ACK_PARSER_QUOTE, STATUS_INVALID_ACK_KEY_START);

                    // Start the key state
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_KEY_START;
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_KEY_START:
                // Accumulate until end of string
                if (curChar == ACK_PARSER_QUOTE) {
                    // End of key start - parse the key name
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos] = '\0';
                    pKinesisVideoStream->fragmentAckParser.curKeyName = getFragmentAckKeyName(pKinesisVideoStream->fragmentAckParser.accumulator);

                    // Move to delimiter state
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_DELIMITER;

                    // Reset the cur position of the accumulator
                    pKinesisVideoStream->fragmentAckParser.curPos = 0;

                } else {
                    // Accumulate it
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos++] = curChar;
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_DELIMITER:
                // Skip whitespaces until the delimiter
                if (!IS_WHITE_SPACE(curChar)) {
                    if (curChar == ACK_PARSER_DELIMITER) {
                        // Move to the body start state
                        pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_BODY_START;
                    }
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_BODY_START:
                // Skip whitespaces until the body start indicator
                if (!IS_WHITE_SPACE(curChar)) {
                    if (curChar == ACK_PARSER_OPEN_BRACE) {
                        // Set the nestedness level
                        level = 1;
                        // Move to the skip body end state
                        pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_SKIP_BODY_BRACE_END;
                    } else if (curChar == ACK_PARSER_OPEN_BRACKET) {
                        // Set the nestedness level
                        level = 1;
                        // Move to the skip body end state
                        pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_SKIP_BODY_BRACKET_END;
                    } else if (curChar == ACK_PARSER_QUOTE) {
                        // Move to text value type
                        pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_TEXT_VALUE;
                    } else if (IS_ACK_START_OF_NUMERIC_VALUE(curChar)) {
                        // Push the cur char to the accumulator
                        pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos++] = curChar;
                        pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_NUMERIC_VALUE;
                    } else {
                        CHK(FALSE, STATUS_INVALID_ACK_INVALID_VALUE_START);
                    }
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_TEXT_VALUE:
                // Accumulate until next quote
                if (curChar == ACK_PARSER_QUOTE) {
                    // Null terminate the string
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos] = '\0';

                    // Process the value
                    CHK_STATUS(processAckValue(&pKinesisVideoStream->fragmentAckParser));

                    // Skip until the end of the value
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_VALUE_END;
                } else {
                    // Accumulate it
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos++] = curChar;
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_NUMERIC_VALUE:
                // Accumulate until delimitation
                if (IS_WHITE_SPACE(curChar)) {
                    // Null terminate the string
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos] = '\0';

                    // Process the value
                    CHK_STATUS(processAckValue(&pKinesisVideoStream->fragmentAckParser));

                    // Skip until the end of the value
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_VALUE_END;
                } else if (curChar == ACK_PARSER_COMMA) {
                    // Null terminate the string
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos] = '\0';

                    // Process the value
                    CHK_STATUS(processAckValue(&pKinesisVideoStream->fragmentAckParser));

                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_VALUE_END;
                } else if (curChar == ACK_PARSER_CLOSE_BRACE) {
                    // Null terminate the string
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos] = '\0';

                    // Process the value
                    CHK_STATUS(processAckValue(&pKinesisVideoStream->fragmentAckParser));

                    // Process the parsed ACK
                    CHK_STATUS(processParsedAck(pKinesisVideoStream));
                } else if (curChar == ACK_PARSER_QUOTE || curChar == ACK_PARSER_OPEN_BRACE || curChar == ACK_PARSER_OPEN_BRACKET ||
                           curChar == ACK_PARSER_CLOSE_BRACKET || curChar == ACK_PARSER_DELIMITER) {
                    // Error condition
                    CHK(FALSE, STATUS_INVALID_ACK_INVALID_VALUE_END);
                } else {
                    // Accumulate it
                    pKinesisVideoStream->fragmentAckParser.accumulator[pKinesisVideoStream->fragmentAckParser.curPos++] = curChar;
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_SKIP_BODY_BRACE_END:
                // Skipping until the end of the body
                if (curChar == ACK_PARSER_OPEN_BRACE) {
                    level++;
                } else if (curChar == ACK_PARSER_CLOSE_BRACE) {
                    level--;
                }

                if (0 == level) {
                    // Body skipped. Move to next state
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_VALUE_END;
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_SKIP_BODY_BRACKET_END:
                // Skipping until the end of the body
                if (curChar == ACK_PARSER_OPEN_BRACKET) {
                    level++;
                } else if (curChar == ACK_PARSER_CLOSE_BRACKET) {
                    level--;
                }

                if (0 == level) {
                    // Body skipped. Move to next state
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_VALUE_END;
                }

                break;

            case FRAGMENT_ACK_PARSER_STATE_VALUE_END:
                // End of the value
                // Skip the whitespaces or comma
                if (IS_WHITE_SPACE(curChar) || ACK_PARSER_COMMA == curChar) {
                    break;
                }

                // If it's a closing curly then we are done
                if (ACK_PARSER_CLOSE_BRACE == curChar) {
                    // Process the parsed ACK
                    CHK_STATUS(processParsedAck(pKinesisVideoStream));
                } else if (ACK_PARSER_QUOTE == curChar) {
                    // Start of the new key
                    pKinesisVideoStream->fragmentAckParser.state = FRAGMENT_ACK_PARSER_STATE_KEY_START;
                } else {
                    // An error is detected
                    CHK(FALSE, STATUS_INVALID_ACK_KEY_START);
                }

                break;
        }
    }

CleanUp:

    // Reset the parser on error
    if (STATUS_FAILED(retStatus)) {
        resetAckParserState(pKinesisVideoStream);
    }

    if (streamLocked) {
        pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoStream->base.lock);
    }

    LEAVES();
    return retStatus;
}