1fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/*
2fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Copyright (C) 2010 The Android Open Source Project
3fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
4fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Licensed under the Apache License, Version 2.0 (the "License");
5fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * you may not use this file except in compliance with the License.
6fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * You may obtain a copy of the License at
7fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
8fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *      http://www.apache.org/licenses/LICENSE-2.0
9fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
10fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Unless required by applicable law or agreed to in writing, software
11fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * distributed under the License is distributed on an "AS IS" BASIS,
12fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * See the License for the specific language governing permissions and
14fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * limitations under the License.
15fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
16fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
17fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <assert.h>
18fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <ctype.h>
19fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <fcntl.h>
20fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <limits.h>
21fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <pthread.h>
222544611b6f37e69955fe7161995b7bacf3ae8fbaAdam Langley#include <stdlib.h>
23fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <string.h>
24fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <sys/stat.h>
25fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <unistd.h>
26fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <openssl/aes.h>
27fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <openssl/hmac.h>
28fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
29fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include "FwdLockConv.h"
30fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include "FwdLockGlue.h"
31fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
32fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define TRUE 1
33fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define FALSE 0
34fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
35fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define INVALID_OFFSET ((off64_t)-1)
36fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
37fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define MAX_NUM_SESSIONS 32
38fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
39fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define OUTPUT_BUFFER_SIZE_INCREMENT 1024
40fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define READ_BUFFER_SIZE 1024
41fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
42fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define MAX_BOUNDARY_LENGTH 70
43fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define MAX_DELIMITER_LENGTH (MAX_BOUNDARY_LENGTH + 4)
44fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
45fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define STRING_LENGTH_INCREMENT 25
46fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
47fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define KEY_SIZE AES_BLOCK_SIZE
48fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define KEY_SIZE_IN_BITS (KEY_SIZE * 8)
49fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
50fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define SHA1_HASH_SIZE 20
51fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
52fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define FWD_LOCK_VERSION 0
53fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define FWD_LOCK_SUBFORMAT 0
54fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define USAGE_RESTRICTION_FLAGS 0
55fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define CONTENT_TYPE_LENGTH_POS 7
56fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define TOP_HEADER_SIZE 8
57fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
58fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
59fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Data type for the parser states of the converter.
60fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
61fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheratypedef enum FwdLockConv_ParserState {
62fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ParserState_WantsOpenDelimiter,
63fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ParserState_WantsMimeHeaders,
64fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ParserState_WantsBinaryEncodedData,
65fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ParserState_WantsBase64EncodedData,
66fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ParserState_Done
67fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} FwdLockConv_ParserState_t;
68fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
69fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
70fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Data type for the scanner states of the converter.
71fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
72fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheratypedef enum FwdLockConv_ScannerState {
73fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsFirstDash,
74fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsSecondDash,
75fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsCR,
76fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsLF,
77fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsBoundary,
78fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsBoundaryEnd,
79fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsMimeHeaderNameStart,
80fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsMimeHeaderName,
81fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsMimeHeaderNameEnd,
82fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsContentTypeStart,
83fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsContentType,
84fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsContentTransferEncodingStart,
85fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_A_OR_I,
86fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_N,
87fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_A,
88fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_R,
89fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_Y,
90fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_S,
91fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_E,
92fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_6,
93fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_4,
94fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_B,
95fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_I,
96fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_Wants_T,
97fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsContentTransferEncodingEnd,
98fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsMimeHeaderValueEnd,
99fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsMimeHeadersEnd,
100fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsByte1,
101fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsByte1_AfterCRLF,
102fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsByte2,
103fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsByte3,
104fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsByte4,
105fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsPadding,
106fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsWhitespace,
107fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF,
108fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_WantsDelimiter
109fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} FwdLockConv_ScannerState_t;
110fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
111fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
112fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Data type for the content transfer encoding.
113fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
114fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheratypedef enum FwdLockConv_ContentTransferEncoding {
115fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ContentTransferEncoding_Undefined,
116fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ContentTransferEncoding_Binary,
117fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ContentTransferEncoding_Base64
118fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} FwdLockConv_ContentTransferEncoding_t;
119fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
120fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
121fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Data type for a dynamically growing string.
122fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
123fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheratypedef struct FwdLockConv_String {
124fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    char *ptr;
125fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t length;
126fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t maxLength;
127fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t lengthIncrement;
128fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} FwdLockConv_String_t;
129fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
130fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
131fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Data type for the per-file state information needed by the converter.
132fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
133fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheratypedef struct FwdLockConv_Session {
134fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ParserState_t parserState;
135fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_t scannerState;
136fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ScannerState_t savedScannerState;
137fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    off64_t numCharsConsumed;
138fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    char delimiter[MAX_DELIMITER_LENGTH];
139fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t delimiterLength;
140fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t delimiterMatchPos;
141fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_String_t mimeHeaderName;
142fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_String_t contentType;
143fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_ContentTransferEncoding_t contentTransferEncoding;
144fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    unsigned char sessionKey[KEY_SIZE];
145fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    void *pEncryptedSessionKey;
146fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t encryptedSessionKeyLength;
147fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    AES_KEY encryptionRoundKeys;
148fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    HMAC_CTX signingContext;
149fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    unsigned char topHeader[TOP_HEADER_SIZE];
150fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    unsigned char counter[AES_BLOCK_SIZE];
151fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    unsigned char keyStream[AES_BLOCK_SIZE];
152fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    int keyStreamIndex;
153fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    unsigned char ch;
154fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t outputBufferSize;
155fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t dataOffset;
156fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t numDataBytes;
157fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} FwdLockConv_Session_t;
158fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
159fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Session_t *sessionPtrs[MAX_NUM_SESSIONS] = { NULL };
160fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
161fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic pthread_mutex_t sessionAcquisitionMutex = PTHREAD_MUTEX_INITIALIZER;
162fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
163fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const FwdLockConv_String_t nullString = { NULL, 0, 0, STRING_LENGTH_INCREMENT };
164fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
165fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const unsigned char topHeaderTemplate[] =
166fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    { 'F', 'W', 'L', 'K', FWD_LOCK_VERSION, FWD_LOCK_SUBFORMAT, USAGE_RESTRICTION_FLAGS };
167fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
168fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const char strContent[] = "content-";
169fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const char strType[] = "type";
170fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const char strTransferEncoding[] = "transfer-encoding";
171fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const char strTextPlain[] = "text/plain";
172fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const char strApplicationVndOmaDrmRightsXml[] = "application/vnd.oma.drm.rights+xml";
173fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const char strApplicationVndOmaDrmContent[] = "application/vnd.oma.drm.content";
174fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
175fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const size_t strlenContent = sizeof strContent - 1;
176fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const size_t strlenTextPlain = sizeof strTextPlain - 1;
177fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
178fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const signed char base64Values[] = {
179fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
180fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
181fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
182fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
183fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
184fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
185fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
186fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
187fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera};
188fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
189fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
190fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Acquires an unused converter session.
191fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
192fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A session ID.
193fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
194fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_AcquireSession() {
195fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    int sessionId = -1;
196fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    int i;
197fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    pthread_mutex_lock(&sessionAcquisitionMutex);
198fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    for (i = 0; i < MAX_NUM_SESSIONS; ++i) {
199fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (sessionPtrs[i] == NULL) {
200fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            sessionPtrs[i] = malloc(sizeof *sessionPtrs[i]);
201fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (sessionPtrs[i] != NULL) {
202fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                sessionId = i;
203fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
204fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            break;
205fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
206fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
207fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    pthread_mutex_unlock(&sessionAcquisitionMutex);
208fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return sessionId;
209fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
210fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
211fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
212fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Checks whether a session ID is in range and currently in use.
213fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
214fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] sessionID A session ID.
215fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
216fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the session ID is in range and currently in use.
217fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
218fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_IsValidSession(int sessionId) {
219fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return 0 <= sessionId && sessionId < MAX_NUM_SESSIONS && sessionPtrs[sessionId] != NULL;
220fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
221fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
222fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
223fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Releases a converter session.
224fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
225fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] sessionID A session ID.
226fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
227fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic void FwdLockConv_ReleaseSession(int sessionId) {
228fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    pthread_mutex_lock(&sessionAcquisitionMutex);
229fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    assert(FwdLockConv_IsValidSession(sessionId));
230fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    memset(sessionPtrs[sessionId], 0, sizeof *sessionPtrs[sessionId]); // Zero out key data.
231fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    free(sessionPtrs[sessionId]);
232fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    sessionPtrs[sessionId] = NULL;
233fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    pthread_mutex_unlock(&sessionAcquisitionMutex);
234fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
235fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
236fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
237fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Derives cryptographically independent keys for encryption and signing from the session key.
238fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
239fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
240fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
241fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
242fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
243fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_DeriveKeys(FwdLockConv_Session_t *pSession) {
244fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
245fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    struct FwdLockConv_DeriveKeys_Data {
246fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        AES_KEY sessionRoundKeys;
247fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        unsigned char value[KEY_SIZE];
248fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        unsigned char key[KEY_SIZE];
2492d45dbd1910a7e51d383e8583017e6f26cd3498aHung Nguyen    };
2502d45dbd1910a7e51d383e8583017e6f26cd3498aHung Nguyen    const size_t kSize = sizeof(struct FwdLockConv_DeriveKeys_Data);
2512d45dbd1910a7e51d383e8583017e6f26cd3498aHung Nguyen    struct FwdLockConv_DeriveKeys_Data *pData = malloc(kSize);
252fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pData == NULL) {
253fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_OutOfMemory;
254fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
255fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (AES_set_encrypt_key(pSession->sessionKey, KEY_SIZE_IN_BITS,
256fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                &pData->sessionRoundKeys) != 0) {
257fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_ProgramError;
258fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
259fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // Encrypt the 16-byte value {0, 0, ..., 0} to produce the encryption key.
260fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            memset(pData->value, 0, KEY_SIZE);
261fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
262fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS,
263fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                    &pSession->encryptionRoundKeys) != 0) {
264fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_ProgramError;
265fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else {
266fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                // Encrypt the 16-byte value {1, 0, ..., 0} to produce the signing key.
267fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                ++pData->value[0];
268fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
269fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                HMAC_CTX_init(&pSession->signingContext);
270fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                HMAC_Init_ex(&pSession->signingContext, pData->key, KEY_SIZE, EVP_sha1(), NULL);
271fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_OK;
272fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
273fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
2742d45dbd1910a7e51d383e8583017e6f26cd3498aHung Nguyen        memset(pData, 0, kSize); // Zero out key data.
275fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        free(pData);
276fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
277fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
278fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
279fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
280fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
28190855078eb989944bca1824058d7231cd68e5021Henrik B Andersson * Checks whether a given character is valid in a boundary. Allows some non-standard characters that
28290855078eb989944bca1824058d7231cd68e5021Henrik B Andersson * are invalid according to RFC 2046 but nevertheless used by one vendor's DRM packager. Note that
28390855078eb989944bca1824058d7231cd68e5021Henrik B Andersson * the boundary may contain leading and internal spaces.
284fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
285fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch The character to check.
286fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
287fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the given character is valid in a boundary.
288fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
289fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_IsBoundaryChar(int ch) {
29090855078eb989944bca1824058d7231cd68e5021Henrik B Andersson    return isalnum(ch) || ch == '\'' || ch == '(' || ch == ')' || ch == '+' || ch == '_' ||
29190855078eb989944bca1824058d7231cd68e5021Henrik B Andersson            ch == ',' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '=' ||
29290855078eb989944bca1824058d7231cd68e5021Henrik B Andersson            ch == '?' || ch == ' ' || ch == '%' || ch == '[' || ch == '&' || ch == '*' || ch == '^';
293fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
294fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
295fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
296fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Checks whether a given character should be considered whitespace, using a narrower definition
297fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * than the standard-library isspace() function.
298fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
299fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch The character to check.
300fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
301fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the given character should be considered whitespace.
302fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
303fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_IsWhitespace(int ch) {
304fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return ch == ' ' || ch == '\t';
305fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
306fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
307fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
308fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Removes trailing spaces from the delimiter.
309fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
310fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
311fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
312fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
313fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
314fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_RightTrimDelimiter(FwdLockConv_Session_t *pSession) {
315fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    while (pSession->delimiterLength > 4 &&
316fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera           pSession->delimiter[pSession->delimiterLength - 1] == ' ') {
317fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        --pSession->delimiterLength;
318fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
319fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pSession->delimiterLength > 4) {
320fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        return FwdLockConv_Status_OK;
321fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
322fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return FwdLockConv_Status_SyntaxError;
323fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
324fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
325fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
326fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Matches the open delimiter.
327fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
328fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
329fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch A character.
330fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
331fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
332fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
333fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_MatchOpenDelimiter(FwdLockConv_Session_t *pSession,
334fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                           int ch) {
335fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status = FwdLockConv_Status_OK;
336fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    switch (pSession->scannerState) {
337fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsFirstDash:
338fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '-') {
339fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash;
340fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
341fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
342fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
343fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
344fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
345fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
346fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsSecondDash:
347fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '-') {
348fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // The delimiter starts with "\r\n--" (the open delimiter may omit the initial "\r\n").
349fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // The rest is the user-defined boundary that should come next.
350fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->delimiter[0] = '\r';
351fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->delimiter[1] = '\n';
352fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->delimiter[2] = '-';
353fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->delimiter[3] = '-';
354fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->delimiterLength = 4;
355fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsBoundary;
356fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
357fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
358fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
359fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
360fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
361fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
362fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsCR:
363fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\r') {
364fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
365fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
366fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
367fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsLF:
368fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\n') {
369fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
370fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch != '\r') {
371fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
372fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
373fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
374fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsBoundary:
375fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsBoundaryChar(ch)) {
376fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // The boundary may contain leading and internal spaces, so trailing spaces will also be
377fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // matched here. These will be removed later.
378fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (pSession->delimiterLength < MAX_DELIMITER_LENGTH) {
379fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->delimiter[pSession->delimiterLength++] = ch;
380fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else if (ch != ' ') {
381fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_SyntaxError;
382fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
383fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
384fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_RightTrimDelimiter(pSession);
385fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
386fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsBoundaryEnd;
387fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
388fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\t') {
389fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_RightTrimDelimiter(pSession);
390fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
391fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
392fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
393fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
394fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
395fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
396fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
397fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsWhitespace:
398fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\r') {
399fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsBoundaryEnd;
400fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
401fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
402fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
403fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
404fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsBoundaryEnd:
405fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\n') {
406fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->parserState = FwdLockConv_ParserState_WantsMimeHeaders;
407fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameStart;
408fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
409fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
410fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
411fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
412fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    default:
413fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_ProgramError;
414fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
415fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
416fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
417fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
418fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
419fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
420fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Checks whether a given character is valid in a MIME header name.
421fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
422fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch The character to check.
423fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
424fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the given character is valid in a MIME header name.
425fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
426fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_IsMimeHeaderNameChar(int ch) {
427fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return isgraph(ch) && ch != ':';
428fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
429fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
430fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
431fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Checks whether a given character is valid in a MIME header value.
432fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
433fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch The character to check.
434fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
435fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the given character is valid in a MIME header value.
436fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
437fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_IsMimeHeaderValueChar(int ch) {
438fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return isgraph(ch) && ch != ';';
439fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
440fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
441fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
442fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Appends a character to the specified dynamically growing string.
443fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
444fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pString A reference to a dynamically growing string.
445fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch The character to append.
446fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
447fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
448fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
449fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_StringAppend(FwdLockConv_String_t *pString, int ch) {
450fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pString->length == pString->maxLength) {
451fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        size_t newMaxLength = pString->maxLength + pString->lengthIncrement;
452fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        char *newPtr = realloc(pString->ptr, newMaxLength + 1);
453fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (newPtr == NULL) {
454fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            return FwdLockConv_Status_OutOfMemory;
455fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
456fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pString->ptr = newPtr;
457fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pString->maxLength = newMaxLength;
458fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
459fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    pString->ptr[pString->length++] = ch;
460fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    pString->ptr[pString->length] = '\0';
461fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return FwdLockConv_Status_OK;
462fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
463fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
464fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
465fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Attempts to recognize the MIME header name and changes the scanner state accordingly.
466fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
467fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
468fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
469fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
470fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
471fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_RecognizeMimeHeaderName(FwdLockConv_Session_t *pSession) {
472fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status = FwdLockConv_Status_OK;
473fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (strncmp(pSession->mimeHeaderName.ptr, strContent, strlenContent) == 0) {
474fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (strcmp(pSession->mimeHeaderName.ptr + strlenContent, strType) == 0) {
475fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (pSession->contentType.ptr == NULL) {
476fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsContentTypeStart;
477fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else {
478fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_SyntaxError;
479fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
480fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (strcmp(pSession->mimeHeaderName.ptr + strlenContent, strTransferEncoding) == 0) {
481fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (pSession->contentTransferEncoding ==
482fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    FwdLockConv_ContentTransferEncoding_Undefined) {
483fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingStart;
484fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else {
485fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_SyntaxError;
486fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
487fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
488fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
489fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
490fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
491fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
492fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
493fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
494fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
495fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
496fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
497fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Applies defaults to missing MIME header values.
498fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
499fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
500fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
501fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
502fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
503fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_ApplyDefaults(FwdLockConv_Session_t *pSession) {
504fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pSession->contentType.ptr == NULL) {
505fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        // Content type is missing: default to "text/plain".
506fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->contentType.ptr = malloc(sizeof strTextPlain);
507fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (pSession->contentType.ptr == NULL) {
508fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            return FwdLockConv_Status_OutOfMemory;
509fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
510fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        memcpy(pSession->contentType.ptr, strTextPlain, sizeof strTextPlain);
511fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->contentType.length = strlenTextPlain;
512fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->contentType.maxLength = strlenTextPlain;
513fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
514fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pSession->contentTransferEncoding == FwdLockConv_ContentTransferEncoding_Undefined) {
515fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        // Content transfer encoding is missing: default to binary.
516fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary;
517fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
518fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return FwdLockConv_Status_OK;
519fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
520fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
521fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
522fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Verifies that the content type is supported.
523fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
524fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
525fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
526fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
527fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
528fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_VerifyContentType(FwdLockConv_Session_t *pSession) {
529fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
530fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pSession->contentType.ptr == NULL) {
531fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_ProgramError;
532fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else if (strcmp(pSession->contentType.ptr, strApplicationVndOmaDrmRightsXml) == 0 ||
533fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera               strcmp(pSession->contentType.ptr, strApplicationVndOmaDrmContent) == 0) {
534fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_UnsupportedFileFormat;
535fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
536fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_OK;
537fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
538fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
539fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
540fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
541fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
542fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Writes the header of the output file.
543fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
544fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
545fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[out] pOutput The output from the conversion process.
546fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
547fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
548fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
549fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_WriteHeader(FwdLockConv_Session_t *pSession,
550fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                    FwdLockConv_Output_t *pOutput) {
551fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
552fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pSession->contentType.length > UCHAR_MAX) {
553fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_SyntaxError;
554fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
555fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->outputBufferSize = OUTPUT_BUFFER_SIZE_INCREMENT;
556fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pOutput->fromConvertData.pBuffer = malloc(pSession->outputBufferSize);
557fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (pOutput->fromConvertData.pBuffer == NULL) {
558fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_OutOfMemory;
559fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
560fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            size_t encryptedSessionKeyPos = TOP_HEADER_SIZE + pSession->contentType.length;
561fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            size_t dataSignaturePos = encryptedSessionKeyPos + pSession->encryptedSessionKeyLength;
562fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            size_t headerSignaturePos = dataSignaturePos + SHA1_HASH_SIZE;
563fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->dataOffset = headerSignaturePos + SHA1_HASH_SIZE;
564fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            memcpy(pSession->topHeader, topHeaderTemplate, sizeof topHeaderTemplate);
565fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->topHeader[CONTENT_TYPE_LENGTH_POS] =
566fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    (unsigned char)pSession->contentType.length;
567fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            memcpy(pOutput->fromConvertData.pBuffer, pSession->topHeader, TOP_HEADER_SIZE);
568fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            memcpy((char *)pOutput->fromConvertData.pBuffer + TOP_HEADER_SIZE,
569fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                   pSession->contentType.ptr, pSession->contentType.length);
570fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            memcpy((char *)pOutput->fromConvertData.pBuffer + encryptedSessionKeyPos,
571fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                   pSession->pEncryptedSessionKey, pSession->encryptedSessionKeyLength);
572fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
573fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // Set the signatures to all zeros for now; they will have to be updated later.
574fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            memset((char *)pOutput->fromConvertData.pBuffer + dataSignaturePos, 0,
575fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                   SHA1_HASH_SIZE);
576fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            memset((char *)pOutput->fromConvertData.pBuffer + headerSignaturePos, 0,
577fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                   SHA1_HASH_SIZE);
578fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
579fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pOutput->fromConvertData.numBytes = pSession->dataOffset;
580fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_OK;
581fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
582fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
583fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
584fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
585fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
586fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
587fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Matches the MIME headers.
588fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
589fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
590fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch A character.
591fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[out] pOutput The output from the conversion process.
592fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
593fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
594fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
595fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_MatchMimeHeaders(FwdLockConv_Session_t *pSession,
596fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                         int ch,
597fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                         FwdLockConv_Output_t *pOutput) {
598fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status = FwdLockConv_Status_OK;
599fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    switch (pSession->scannerState) {
600fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsMimeHeaderNameStart:
601fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsMimeHeaderNameChar(ch)) {
602fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->mimeHeaderName.length = 0;
603fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_StringAppend(&pSession->mimeHeaderName, tolower(ch));
604fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
605fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderName;
606fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
607fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
608fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeadersEnd;
609fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
610fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
611fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
612fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
613fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsMimeHeaderName:
614fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsMimeHeaderNameChar(ch)) {
615fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_StringAppend(&pSession->mimeHeaderName, tolower(ch));
616fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == ':') {
617fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_RecognizeMimeHeaderName(pSession);
618fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (FwdLockConv_IsWhitespace(ch)) {
619fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameEnd;
620fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
621fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
622fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
623fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
624fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsMimeHeaderNameEnd:
625fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == ':') {
626fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_RecognizeMimeHeaderName(pSession);
627fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
628fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
629fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
630fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
631fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsContentTypeStart:
632fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsMimeHeaderValueChar(ch)) {
633fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_StringAppend(&pSession->contentType, tolower(ch));
634fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
635fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsContentType;
636fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
637fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
638fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
639fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
640fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
641fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsContentType:
642fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsMimeHeaderValueChar(ch)) {
643fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_StringAppend(&pSession->contentType, tolower(ch));
644fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == ';') {
645fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
646fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
647fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
648fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (FwdLockConv_IsWhitespace(ch)) {
649fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderValueEnd;
650fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
651fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
652fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
653fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
654fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsContentTransferEncodingStart:
655fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'b' || ch == 'B') {
656fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_A_OR_I;
657fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '7' || ch == '8') {
658fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_B;
659fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
660fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
661fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
662fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
663fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_A_OR_I:
664fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'i' || ch == 'I') {
665fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_N;
666fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == 'a' || ch == 'A') {
667fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_S;
668fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
669fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
670fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
671fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
672fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_N:
673fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'n' || ch == 'N') {
674fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_A;
675fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
676fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
677fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
678fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
679fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_A:
680fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'a' || ch == 'A') {
681fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_R;
682fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
683fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
684fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
685fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
686fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_R:
687fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'r' || ch == 'R') {
688fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_Y;
689fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
690fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
691fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
692fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
693fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_Y:
694fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'y' || ch == 'Y') {
695fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary;
696fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd;
697fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
698fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
699fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
700fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
701fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_S:
702fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 's' || ch == 'S') {
703fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_E;
704fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
705fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
706fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
707fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
708fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_E:
709fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'e' || ch == 'E') {
710fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_6;
711fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
712fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
713fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
714fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
715fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_6:
716fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '6') {
717fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_4;
718fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
719fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
720fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
721fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
722fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_4:
723fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '4') {
724fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Base64;
725fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd;
726fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
727fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
728fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
729fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
730fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_B:
731fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'b' || ch == 'B') {
732fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_I;
733fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
734fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
735fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
736fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
737fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_I:
738fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 'i' || ch == 'I') {
739fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_Wants_T;
740fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
741fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
742fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
743fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
744fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_Wants_T:
745fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == 't' || ch == 'T') {
746fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary;
747fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd;
748fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
749fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
750fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
751fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
752fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsContentTransferEncodingEnd:
753fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == ';') {
754fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
755fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
756fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
757fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (FwdLockConv_IsWhitespace(ch)) {
758fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderValueEnd;
759fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
760fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
761fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
762fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
763fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsMimeHeaderValueEnd:
764fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == ';') {
765fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
766fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
767fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
768fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
769fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
770fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
771fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
772fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsCR:
773fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\r') {
774fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
775fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
776fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
777fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsLF:
778fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\n') {
779fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameStart;
780fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
781fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
782fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
783fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
784fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsMimeHeadersEnd:
785fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\n') {
786fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_ApplyDefaults(pSession);
787fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
788fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_VerifyContentType(pSession);
789fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
790fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
791fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_WriteHeader(pSession, pOutput);
792fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
793fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
794fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                if (pSession->contentTransferEncoding ==
795fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        FwdLockConv_ContentTransferEncoding_Binary) {
796fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    pSession->parserState = FwdLockConv_ParserState_WantsBinaryEncodedData;
797fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                } else {
798fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    pSession->parserState = FwdLockConv_ParserState_WantsBase64EncodedData;
799fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                }
800fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsByte1;
801fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
802fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
803fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
804fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
805fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
806fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    default:
807fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_ProgramError;
808fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
809fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
810fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
811fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
812fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
813fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
814fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Increments the counter, treated as a 16-byte little-endian number, by one.
815fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
816fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
817fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
818fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic void FwdLockConv_IncrementCounter(FwdLockConv_Session_t *pSession) {
819fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    size_t i = 0;
820fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    while ((++pSession->counter[i] == 0) && (++i < AES_BLOCK_SIZE))
821fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        ;
822fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
823fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
824fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
825fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Encrypts the given character and writes it to the output buffer.
826fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
827fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
828fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch The character to encrypt and write.
829fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pOutput The output from the conversion process.
830fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
831fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
832fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
833fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_WriteEncryptedChar(FwdLockConv_Session_t *pSession,
834fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                           unsigned char ch,
835fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                           FwdLockConv_Output_t *pOutput) {
836fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pOutput->fromConvertData.numBytes == pSession->outputBufferSize) {
837fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        void *pBuffer;
838fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->outputBufferSize += OUTPUT_BUFFER_SIZE_INCREMENT;
839fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pBuffer = realloc(pOutput->fromConvertData.pBuffer, pSession->outputBufferSize);
840fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (pBuffer == NULL) {
841fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            return FwdLockConv_Status_OutOfMemory;
842fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
843fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pOutput->fromConvertData.pBuffer = pBuffer;
844fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
845fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (++pSession->keyStreamIndex == AES_BLOCK_SIZE) {
846fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        FwdLockConv_IncrementCounter(pSession);
847fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->keyStreamIndex = 0;
848fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
849fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pSession->keyStreamIndex == 0) {
850fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        AES_encrypt(pSession->counter, pSession->keyStream, &pSession->encryptionRoundKeys);
851fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
852fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    ch ^= pSession->keyStream[pSession->keyStreamIndex];
853fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    ((unsigned char *)pOutput->fromConvertData.pBuffer)[pOutput->fromConvertData.numBytes++] = ch;
854fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    ++pSession->numDataBytes;
855fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return FwdLockConv_Status_OK;
856fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
857fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
858fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
859fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Matches binary-encoded content data and encrypts it, while looking out for the close delimiter.
860fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
861fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
862fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch A character.
863fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pOutput The output from the conversion process.
864fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
865fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
866fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
867fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_MatchBinaryEncodedData(FwdLockConv_Session_t *pSession,
868fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                               int ch,
869fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                               FwdLockConv_Output_t *pOutput) {
870fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status = FwdLockConv_Status_OK;
871fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    switch (pSession->scannerState) {
872fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsByte1:
873fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch != pSession->delimiter[pSession->delimiterMatchPos]) {
874fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // The partial match of the delimiter turned out to be spurious. Flush the matched bytes
875fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // to the output buffer and start over.
876fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            size_t i;
877fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            for (i = 0; i < pSession->delimiterMatchPos; ++i) {
878fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_WriteEncryptedChar(pSession, pSession->delimiter[i], pOutput);
879fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                if (status != FwdLockConv_Status_OK) {
880fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    return status;
881fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                }
882fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
883fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->delimiterMatchPos = 0;
884fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
885fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch != pSession->delimiter[pSession->delimiterMatchPos]) {
886fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // The current character isn't part of the delimiter. Write it to the output buffer.
887fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_WriteEncryptedChar(pSession, ch, pOutput);
888fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (++pSession->delimiterMatchPos == pSession->delimiterLength) {
889fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // The entire delimiter has been matched. The only valid characters now are the "--"
890fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // that complete the close delimiter (no more message parts are expected).
891fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
892fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
893fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
894fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsFirstDash:
895fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '-') {
896fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash;
897fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
898fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
899fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
900fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
901fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsSecondDash:
902fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '-') {
903fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->parserState = FwdLockConv_ParserState_Done;
904fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
905fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
906fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
907fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
908fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    default:
909fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_ProgramError;
910fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
911fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
912fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
913fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
914fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
915fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
916fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Checks whether a given character is valid in base64-encoded data.
917fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
918fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch The character to check.
919fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
920fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the given character is valid in base64-encoded data.
921fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
922fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockConv_IsBase64Char(int ch) {
923fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return 0 <= ch && ch <= 'z' && base64Values[ch] >= 0;
924fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
925fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
926fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
927fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Matches base64-encoded content data and encrypts it, while looking out for the close delimiter.
928fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
929fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
930fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch A character.
931fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pOutput The output from the conversion process.
932fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
933fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
934fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
935fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_MatchBase64EncodedData(FwdLockConv_Session_t *pSession,
936fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                               int ch,
937fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                               FwdLockConv_Output_t *pOutput) {
938fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status = FwdLockConv_Status_OK;
939fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    switch (pSession->scannerState) {
940fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsByte1:
941fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsByte1_AfterCRLF:
942fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsBase64Char(ch)) {
943fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->ch = base64Values[ch] << 2;
944fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsByte2;
945fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
946fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->savedScannerState = FwdLockConv_ScannerState_WantsByte1_AfterCRLF;
947fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
948fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '-') {
949fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (pSession->scannerState == FwdLockConv_ScannerState_WantsByte1_AfterCRLF) {
950fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->delimiterMatchPos = 3;
951fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsDelimiter;
952fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else {
953fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_SyntaxError;
954fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
955fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
956fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
957fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
958fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
959fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsByte2:
960fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsBase64Char(ch)) {
961fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->ch |= base64Values[ch] >> 4;
962fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput);
963fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
964fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->ch = base64Values[ch] << 4;
965fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsByte3;
966fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
967fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
968fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->savedScannerState = pSession->scannerState;
969fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
970fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
971fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
972fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
973fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
974fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsByte3:
975fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsBase64Char(ch)) {
976fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->ch |= base64Values[ch] >> 2;
977fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput);
978fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
979fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->ch = base64Values[ch] << 6;
980fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsByte4;
981fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
982fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
983fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->savedScannerState = pSession->scannerState;
984fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
985fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '=') {
986fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsPadding;
987fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
988fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
989fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
990fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
991fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsByte4:
992fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (FwdLockConv_IsBase64Char(ch)) {
993fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->ch |= base64Values[ch];
994fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput);
995fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
996fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsByte1;
997fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
998fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '\r') {
999fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->savedScannerState = pSession->scannerState;
1000fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
1001fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '=') {
1002fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
1003fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (!FwdLockConv_IsWhitespace(ch)) {
1004fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1005fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1006fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1007fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsLF:
1008fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\n') {
1009fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = pSession->savedScannerState;
1010fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1011fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1012fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1013fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1014fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsPadding:
1015fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '=') {
1016fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
1017fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1018fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1019fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1020fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1021fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsWhitespace:
1022fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF:
1023fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '\r') {
1024fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->savedScannerState = FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF;
1025fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
1026fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (ch == '-') {
1027fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (pSession->scannerState == FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF) {
1028fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->delimiterMatchPos = 3;
1029fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->scannerState = FwdLockConv_ScannerState_WantsDelimiter;
1030fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else {
1031fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_SyntaxError;
1032fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
1033fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (FwdLockConv_IsWhitespace(ch)) {
1034fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
1035fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1036fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1037fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1038fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1039fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsDelimiter:
1040fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch != pSession->delimiter[pSession->delimiterMatchPos]) {
1041fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1042fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (++pSession->delimiterMatchPos == pSession->delimiterLength) {
1043fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
1044fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1045fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1046fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsFirstDash:
1047fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '-') {
1048fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash;
1049fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1050fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1051fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1052fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1053fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ScannerState_WantsSecondDash:
1054fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (ch == '-') {
1055fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->parserState = FwdLockConv_ParserState_Done;
1056fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1057fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1058fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1059fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1060fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    default:
1061fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_ProgramError;
1062fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1063fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
1064fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
1065fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
1066fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
1067fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/**
1068fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Pushes a single character into the converter's state machine.
1069fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
1070fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a converter session.
1071fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] ch A character.
1072fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pOutput The output from the conversion process.
1073fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *
1074fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A status code.
1075fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */
1076fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockConv_Status_t FwdLockConv_PushChar(FwdLockConv_Session_t *pSession,
1077fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                 int ch,
1078fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                 FwdLockConv_Output_t *pOutput) {
1079fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
1080fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    ++pSession->numCharsConsumed;
1081fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    switch (pSession->parserState) {
1082fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ParserState_WantsOpenDelimiter:
1083fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_MatchOpenDelimiter(pSession, ch);
1084fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1085fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ParserState_WantsMimeHeaders:
1086fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_MatchMimeHeaders(pSession, ch, pOutput);
1087fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1088fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ParserState_WantsBinaryEncodedData:
1089fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_MatchBinaryEncodedData(pSession, ch, pOutput);
1090fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1091fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ParserState_WantsBase64EncodedData:
109290855078eb989944bca1824058d7231cd68e5021Henrik B Andersson        if (ch == '\n' && pSession->scannerState != FwdLockConv_ScannerState_WantsLF) {
109390855078eb989944bca1824058d7231cd68e5021Henrik B Andersson            // Repair base64-encoded data that doesn't have carriage returns in its line breaks.
109490855078eb989944bca1824058d7231cd68e5021Henrik B Andersson            status = FwdLockConv_MatchBase64EncodedData(pSession, '\r', pOutput);
109590855078eb989944bca1824058d7231cd68e5021Henrik B Andersson            if (status != FwdLockConv_Status_OK) {
109690855078eb989944bca1824058d7231cd68e5021Henrik B Andersson                break;
109790855078eb989944bca1824058d7231cd68e5021Henrik B Andersson            }
109890855078eb989944bca1824058d7231cd68e5021Henrik B Andersson        }
1099fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_MatchBase64EncodedData(pSession, ch, pOutput);
1100fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1101fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    case FwdLockConv_ParserState_Done:
1102fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_OK;
1103fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1104fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    default:
1105fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_ProgramError;
1106fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        break;
1107fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
1108fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
1109fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
1110fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
1111fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat DalbeheraFwdLockConv_Status_t FwdLockConv_OpenSession(int *pSessionId, FwdLockConv_Output_t *pOutput) {
1112fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
1113fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pSessionId == NULL || pOutput == NULL) {
1114fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_InvalidArgument;
1115fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
1116fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        *pSessionId = FwdLockConv_AcquireSession();
1117fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (*pSessionId < 0) {
1118fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_TooManySessions;
1119fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1120fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            FwdLockConv_Session_t *pSession = sessionPtrs[*pSessionId];
1121fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pSession->encryptedSessionKeyLength = FwdLockGlue_GetEncryptedKeyLength(KEY_SIZE);
1122fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (pSession->encryptedSessionKeyLength < AES_BLOCK_SIZE) {
1123fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                // The encrypted session key is used as the CTR-mode nonce, so it must be at least
1124fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                // the size of a single AES block.
1125fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_ProgramError;
1126fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else {
1127fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                pSession->pEncryptedSessionKey = malloc(pSession->encryptedSessionKeyLength);
1128fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                if (pSession->pEncryptedSessionKey == NULL) {
1129fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    status = FwdLockConv_Status_OutOfMemory;
1130fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                } else {
1131fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    if (!FwdLockGlue_GetRandomNumber(pSession->sessionKey, KEY_SIZE)) {
1132fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        status = FwdLockConv_Status_RandomNumberGenerationFailed;
1133fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    } else if (!FwdLockGlue_EncryptKey(pSession->sessionKey, KEY_SIZE,
1134fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                       pSession->pEncryptedSessionKey,
1135fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                       pSession->encryptedSessionKeyLength)) {
1136fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        status = FwdLockConv_Status_KeyEncryptionFailed;
1137fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    } else {
1138fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        status = FwdLockConv_DeriveKeys(pSession);
1139fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    }
1140fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    if (status == FwdLockConv_Status_OK) {
1141fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        memset(pSession->sessionKey, 0, KEY_SIZE); // Zero out key data.
1142fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        memcpy(pSession->counter, pSession->pEncryptedSessionKey, AES_BLOCK_SIZE);
1143fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->parserState = FwdLockConv_ParserState_WantsOpenDelimiter;
1144fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
1145fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->numCharsConsumed = 0;
1146fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->delimiterMatchPos = 0;
1147fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->mimeHeaderName = nullString;
1148fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->contentType = nullString;
1149fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->contentTransferEncoding =
1150fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                FwdLockConv_ContentTransferEncoding_Undefined;
1151fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->keyStreamIndex = -1;
1152fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pOutput->fromConvertData.pBuffer = NULL;
1153fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pOutput->fromConvertData.errorPos = INVALID_OFFSET;
1154fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    } else {
1155fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        free(pSession->pEncryptedSessionKey);
1156fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    }
1157fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                }
1158fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
1159fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status != FwdLockConv_Status_OK) {
1160fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                FwdLockConv_ReleaseSession(*pSessionId);
1161fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                *pSessionId = -1;
1162fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
1163fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1164fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
1165fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
1166fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
1167fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
1168fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat DalbeheraFwdLockConv_Status_t FwdLockConv_ConvertData(int sessionId,
1169fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                             const void *pBuffer,
1170fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                             size_t numBytes,
1171fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                             FwdLockConv_Output_t *pOutput) {
1172fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
1173fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (!FwdLockConv_IsValidSession(sessionId) || pBuffer == NULL || pOutput == NULL) {
1174fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_InvalidArgument;
1175fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
1176fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        size_t i;
1177fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        FwdLockConv_Session_t *pSession = sessionPtrs[sessionId];
1178fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->dataOffset = 0;
1179fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pSession->numDataBytes = 0;
1180fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        pOutput->fromConvertData.numBytes = 0;
1181fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_OK;
1182fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
1183fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        for (i = 0; i < numBytes; ++i) {
1184fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_PushChar(pSession, ((char *)pBuffer)[i], pOutput);
1185fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status != FwdLockConv_Status_OK) {
1186fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                break;
1187fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
1188fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1189fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (status == FwdLockConv_Status_OK) {
1190fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // Update the data signature.
1191fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            HMAC_Update(&pSession->signingContext,
1192fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        &((unsigned char *)pOutput->fromConvertData.pBuffer)[pSession->dataOffset],
1193fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        pSession->numDataBytes);
1194fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else if (status == FwdLockConv_Status_SyntaxError) {
1195fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pOutput->fromConvertData.errorPos = pSession->numCharsConsumed;
1196fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1197fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
1198fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
1199fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
1200fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
1201fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat DalbeheraFwdLockConv_Status_t FwdLockConv_CloseSession(int sessionId, FwdLockConv_Output_t *pOutput) {
1202fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
1203fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (!FwdLockConv_IsValidSession(sessionId) || pOutput == NULL) {
1204fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_InvalidArgument;
1205fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
1206fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        FwdLockConv_Session_t *pSession = sessionPtrs[sessionId];
1207fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        free(pOutput->fromConvertData.pBuffer);
1208fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (pSession->parserState != FwdLockConv_ParserState_Done) {
1209fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pOutput->fromCloseSession.errorPos = pSession->numCharsConsumed;
1210fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_SyntaxError;
1211fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1212fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            // Finalize the data signature.
121390855078eb989944bca1824058d7231cd68e5021Henrik B Andersson            unsigned int signatureSize = SHA1_HASH_SIZE;
1214fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            HMAC_Final(&pSession->signingContext, pOutput->fromCloseSession.signatures,
1215fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                       &signatureSize);
1216fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (signatureSize != SHA1_HASH_SIZE) {
1217fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                status = FwdLockConv_Status_ProgramError;
1218fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            } else {
1219fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                // Calculate the header signature, which is a signature of the rest of the header
1220fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                // including the data signature.
1221fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
1222fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE);
1223fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->contentType.ptr,
1224fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            pSession->contentType.length);
1225fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
1226fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            pSession->encryptedSessionKeyLength);
1227fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                HMAC_Update(&pSession->signingContext, pOutput->fromCloseSession.signatures,
122890855078eb989944bca1824058d7231cd68e5021Henrik B Andersson                            SHA1_HASH_SIZE);
122990855078eb989944bca1824058d7231cd68e5021Henrik B Andersson                HMAC_Final(&pSession->signingContext,
123090855078eb989944bca1824058d7231cd68e5021Henrik B Andersson                           &pOutput->fromCloseSession.signatures[SHA1_HASH_SIZE], &signatureSize);
1231fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                if (signatureSize != SHA1_HASH_SIZE) {
1232fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    status = FwdLockConv_Status_ProgramError;
1233fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                } else {
1234fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    pOutput->fromCloseSession.fileOffset = TOP_HEADER_SIZE +
1235fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            pSession->contentType.length + pSession->encryptedSessionKeyLength;
1236fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    status = FwdLockConv_Status_OK;
1237fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                }
1238fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
1239fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            pOutput->fromCloseSession.errorPos = INVALID_OFFSET;
1240fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1241fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        free(pSession->mimeHeaderName.ptr);
1242fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        free(pSession->contentType.ptr);
1243fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        free(pSession->pEncryptedSessionKey);
1244fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        HMAC_CTX_cleanup(&pSession->signingContext);
1245fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        FwdLockConv_ReleaseSession(sessionId);
1246fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
1247fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
1248fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
1249fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera
1250fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat DalbeheraFwdLockConv_Status_t FwdLockConv_ConvertOpenFile(int inputFileDesc,
1251fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                 FwdLockConv_ReadFunc_t *fpReadFunc,
1252fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                 int outputFileDesc,
1253fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                 FwdLockConv_WriteFunc_t *fpWriteFunc,
1254fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                 FwdLockConv_LSeekFunc_t *fpLSeekFunc,
1255fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                 off64_t *pErrorPos) {
1256fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    FwdLockConv_Status_t status;
1257fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (pErrorPos != NULL) {
1258fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        *pErrorPos = INVALID_OFFSET;
1259fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
1260fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    if (fpReadFunc == NULL || fpWriteFunc == NULL || fpLSeekFunc == NULL || inputFileDesc < 0 ||
1261fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        outputFileDesc < 0) {
1262fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        status = FwdLockConv_Status_InvalidArgument;
1263fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    } else {
1264fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        char *pReadBuffer = malloc(READ_BUFFER_SIZE);
1265fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        if (pReadBuffer == NULL) {
1266fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_Status_OutOfMemory;
1267fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        } else {
1268fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            int sessionId;
1269fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            FwdLockConv_Output_t output;
1270fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            status = FwdLockConv_OpenSession(&sessionId, &output);
1271fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            if (status == FwdLockConv_Status_OK) {
1272fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                ssize_t numBytesRead;
1273fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                FwdLockConv_Status_t closeStatus;
1274fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                while ((numBytesRead =
1275fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        fpReadFunc(inputFileDesc, pReadBuffer, READ_BUFFER_SIZE)) > 0) {
1276fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    status = FwdLockConv_ConvertData(sessionId, pReadBuffer, (size_t)numBytesRead,
1277fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                     &output);
1278fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    if (status == FwdLockConv_Status_OK) {
1279fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        if (output.fromConvertData.pBuffer != NULL &&
1280fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            output.fromConvertData.numBytes > 0) {
1281fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            ssize_t numBytesWritten = fpWriteFunc(outputFileDesc,
1282fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                                  output.fromConvertData.pBuffer,
1283fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                                                  output.fromConvertData.numBytes);
1284fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            if (numBytesWritten != (ssize_t)output.fromConvertData.numBytes) {
1285fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                status = FwdLockConv_Status_FileWriteError;
1286fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                break;
1287fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            }
1288fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        }
1289fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    } else {
1290fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        if (status == FwdLockConv_Status_SyntaxError && pErrorPos != NULL) {
1291fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            *pErrorPos = output.fromConvertData.errorPos;
1292fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        }
1293fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        break;
1294fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    }
1295fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                } // end while
1296fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                if (numBytesRead < 0) {
1297fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    status = FwdLockConv_Status_FileReadError;
1298fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                }
1299fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                closeStatus = FwdLockConv_CloseSession(sessionId, &output);
1300fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                if (status == FwdLockConv_Status_OK) {
1301fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    if (closeStatus != FwdLockConv_Status_OK) {
1302fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        if (closeStatus == FwdLockConv_Status_SyntaxError && pErrorPos != NULL) {
1303fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                            *pErrorPos = output.fromCloseSession.errorPos;
1304fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        }
1305fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        status = closeStatus;
1306fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    } else if (fpLSeekFunc(outputFileDesc, output.fromCloseSession.fileOffset,
1307fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                           SEEK_SET) < 0) {
1308fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        status = FwdLockConv_Status_FileSeekError;
1309fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    } else if (fpWriteFunc(outputFileDesc, output.fromCloseSession.signatures,
1310fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                                           FWD_LOCK_SIGNATURES_SIZE) != FWD_LOCK_SIGNATURES_SIZE) {
1311fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                        status = FwdLockConv_Status_FileWriteError;
1312fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                    }
1313fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera                }
1314fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            }
1315fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera            free(pReadBuffer);
1316fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera        }
1317fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    }
1318fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera    return status;
1319fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera}
1320