1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15**********/
16// "liveMedia"
17// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
18// Abstract class for parsing a byte stream
19// Implementation
20
21#include "StreamParser.hh"
22
23#include <string.h>
24#include <stdlib.h>
25
26#define BANK_SIZE 150000
27
28void StreamParser::flushInput() {
29 fCurParserIndex = fSavedParserIndex = 0;
30 fSavedRemainingUnparsedBits = fRemainingUnparsedBits = 0;
31 fTotNumValidBytes = 0;
32}
33
34StreamParser::StreamParser(FramedSource* inputSource,
35 FramedSource::onCloseFunc* onInputCloseFunc,
36 void* onInputCloseClientData,
37 clientContinueFunc* clientContinueFunc,
38 void* clientContinueClientData)
39 : fInputSource(inputSource), fClientOnInputCloseFunc(onInputCloseFunc),
40 fClientOnInputCloseClientData(onInputCloseClientData),
41 fClientContinueFunc(clientContinueFunc),
42 fClientContinueClientData(clientContinueClientData),
43 fSavedParserIndex(0), fSavedRemainingUnparsedBits(0),
44 fCurParserIndex(0), fRemainingUnparsedBits(0),
45 fTotNumValidBytes(0), fHaveSeenEOF(False) {
46 fBank[0] = new unsigned char[BANK_SIZE];
47 fBank[1] = new unsigned char[BANK_SIZE];
48 fCurBankNum = 0;
49 fCurBank = fBank[fCurBankNum];
50
51 fLastSeenPresentationTime.tv_sec = 0; fLastSeenPresentationTime.tv_usec = 0;
52}
53
54StreamParser::~StreamParser() {
55 delete[] fBank[0]; delete[] fBank[1];
56}
57
58void StreamParser::saveParserState() {
59 fSavedParserIndex = fCurParserIndex;
60 fSavedRemainingUnparsedBits = fRemainingUnparsedBits;
61}
62
63void StreamParser::restoreSavedParserState() {
64 fCurParserIndex = fSavedParserIndex;
65 fRemainingUnparsedBits = fSavedRemainingUnparsedBits;
66}
67
68void StreamParser::skipBits(unsigned numBits) {
69 if (numBits <= fRemainingUnparsedBits) {
70 fRemainingUnparsedBits -= numBits;
71 } else {
72 numBits -= fRemainingUnparsedBits;
73
74 unsigned numBytesToExamine = (numBits+7)/8; // round up
75 ensureValidBytes(numBytesToExamine);
76 fCurParserIndex += numBytesToExamine;
77
78 fRemainingUnparsedBits = 8*numBytesToExamine - numBits;
79 }
80}
81
82unsigned StreamParser::getBits(unsigned numBits) {
83 if (numBits <= fRemainingUnparsedBits) {
84 unsigned char lastByte = *lastParsed();
85 lastByte >>= (fRemainingUnparsedBits - numBits);
86 fRemainingUnparsedBits -= numBits;
87
88 return (unsigned)lastByte &~ ((~0u)<<numBits);
89 } else {
90 unsigned char lastByte;
91 if (fRemainingUnparsedBits > 0) {
92 lastByte = *lastParsed();
93 } else {
94 lastByte = 0;
95 }
96
97 unsigned remainingBits = numBits - fRemainingUnparsedBits; // > 0
98
99 // For simplicity, read the next 4 bytes, even though we might not
100 // need all of them here:
101 unsigned result = test4Bytes();
102
103 result >>= (32 - remainingBits);
104 result |= (lastByte << remainingBits);
105 if (numBits < 32) result &=~ ((~0u)<<numBits);
106
107 unsigned const numRemainingBytes = (remainingBits+7)/8;
108 fCurParserIndex += numRemainingBytes;
109 fRemainingUnparsedBits = 8*numRemainingBytes - remainingBits;
110
111 return result;
112 }
113}
114
115unsigned StreamParser::bankSize() const {
116 return BANK_SIZE;
117}
118
119#define NO_MORE_BUFFERED_INPUT 1
120
121void StreamParser::ensureValidBytes1(unsigned numBytesNeeded) {
122 // We need to read some more bytes from the input source.
123 // First, clarify how much data to ask for:
124 unsigned maxInputFrameSize = fInputSource->maxFrameSize();
125 if (maxInputFrameSize > numBytesNeeded) numBytesNeeded = maxInputFrameSize;
126
127 // First, check whether these new bytes would overflow the current
128 // bank. If so, start using a new bank now.
129 if (fCurParserIndex + numBytesNeeded > BANK_SIZE) {
130 // Swap banks, but save any still-needed bytes from the old bank:
131 unsigned numBytesToSave = fTotNumValidBytes - fSavedParserIndex;
132 unsigned char const* from = &curBank()[fSavedParserIndex];
133
134 fCurBankNum = (fCurBankNum + 1)%2;
135 fCurBank = fBank[fCurBankNum];
136 memmove(curBank(), from, numBytesToSave);
137 fCurParserIndex = fCurParserIndex - fSavedParserIndex;
138 fSavedParserIndex = 0;
139 fTotNumValidBytes = numBytesToSave;
140 }
141
142 // ASSERT: fCurParserIndex + numBytesNeeded > fTotNumValidBytes
143 // && fCurParserIndex + numBytesNeeded <= BANK_SIZE
144 if (fCurParserIndex + numBytesNeeded > BANK_SIZE) {
145 // If this happens, it means that we have too much saved parser state.
146 // To fix this, increase BANK_SIZE as appropriate.
147 fInputSource->envir() << "StreamParser internal error ("
148 << fCurParserIndex << " + "
149 << numBytesNeeded << " > "
150 << BANK_SIZE << ")\n";
151 fInputSource->envir().internalError();
152 }
153
154 // Try to read as many new bytes as will fit in the current bank:
155 unsigned maxNumBytesToRead = BANK_SIZE - fTotNumValidBytes;
156 fInputSource->getNextFrame(&curBank()[fTotNumValidBytes],
157 maxNumBytesToRead,
158 afterGettingBytes, this,
159 onInputClosure, this);
160
161 throw NO_MORE_BUFFERED_INPUT;
162}
163
164void StreamParser::afterGettingBytes(void* clientData,
165 unsigned numBytesRead,
166 unsigned /*numTruncatedBytes*/,
167 struct timeval presentationTime,
168 unsigned /*durationInMicroseconds*/){
169 StreamParser* parser = (StreamParser*)clientData;
170 if (parser != NULL) parser->afterGettingBytes1(numBytesRead, presentationTime);
171}
172
173void StreamParser::afterGettingBytes1(unsigned numBytesRead, struct timeval presentationTime) {
174 // Sanity check: Make sure we didn't get too many bytes for our bank:
175 if (fTotNumValidBytes + numBytesRead > BANK_SIZE) {
176 fInputSource->envir()
177 << "StreamParser::afterGettingBytes() warning: read "
178 << numBytesRead << " bytes; expected no more than "
179 << BANK_SIZE - fTotNumValidBytes << "\n";
180 }
181
182 fLastSeenPresentationTime = presentationTime;
183
184 unsigned char* ptr = &curBank()[fTotNumValidBytes];
185 fTotNumValidBytes += numBytesRead;
186
187 // Continue our original calling source where it left off:
188 restoreSavedParserState();
189 // Sigh... this is a crock; things would have been a lot simpler
190 // here if we were using threads, with synchronous I/O...
191 fClientContinueFunc(fClientContinueClientData, ptr, numBytesRead, presentationTime);
192}
193
194void StreamParser::onInputClosure(void* clientData) {
195 StreamParser* parser = (StreamParser*)clientData;
196 if (parser != NULL) parser->onInputClosure1();
197}
198
199void StreamParser::onInputClosure1() {
200 if (!fHaveSeenEOF) {
201 // We're hitting EOF for the first time. Set our 'EOF' flag, and continue parsing, as if we'd just read 0 bytes of data.
202 // This allows the parser to re-parse any remaining unparsed data (perhaps while testing for EOF at the end):
203 fHaveSeenEOF = True;
204 afterGettingBytes1(0, fLastSeenPresentationTime);
205 } else {
206 // We're hitting EOF for the second time. Now, we handle the source input closure:
207 fHaveSeenEOF = False;
208 if (fClientOnInputCloseFunc != NULL) (*fClientOnInputCloseFunc)(fClientOnInputCloseClientData);
209 }
210}
211