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