1 | /********** |
2 | This library is free software; you can redistribute it and/or modify it under |
3 | the terms of the GNU Lesser General Public License as published by the |
4 | Free Software Foundation; either version 3 of the License, or (at your |
5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
6 | |
7 | This library is distributed in the hope that it will be useful, but WITHOUT |
8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
10 | more details. |
11 | |
12 | You should have received a copy of the GNU Lesser General Public License |
13 | along with this library; if not, write to the Free Software Foundation, Inc., |
14 | 51 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 | // C++ header |
20 | |
21 | #ifndef _STREAM_PARSER_HH |
22 | #define _STREAM_PARSER_HH |
23 | |
24 | #ifndef _FRAMED_SOURCE_HH |
25 | #include "FramedSource.hh" |
26 | #endif |
27 | |
28 | class StreamParser { |
29 | public: |
30 | virtual void flushInput(); |
31 | |
32 | protected: // we're a virtual base class |
33 | typedef void (clientContinueFunc)(void* clientData, |
34 | unsigned char* ptr, unsigned size, |
35 | struct timeval presentationTime); |
36 | StreamParser(FramedSource* inputSource, |
37 | FramedSource::onCloseFunc* onInputCloseFunc, |
38 | void* onInputCloseClientData, |
39 | clientContinueFunc* clientContinueFunc, |
40 | void* clientContinueClientData); |
41 | virtual ~StreamParser(); |
42 | |
43 | void saveParserState(); |
44 | virtual void restoreSavedParserState(); |
45 | |
46 | u_int32_t get4Bytes() { // byte-aligned; returned in big-endian order |
47 | u_int32_t result = test4Bytes(); |
48 | fCurParserIndex += 4; |
49 | fRemainingUnparsedBits = 0; |
50 | |
51 | return result; |
52 | } |
53 | u_int32_t test4Bytes() { // as above, but doesn't advance ptr |
54 | ensureValidBytes(4); |
55 | |
56 | unsigned char const* ptr = nextToParse(); |
57 | return (ptr[0]<<24)|(ptr[1]<<16)|(ptr[2]<<8)|ptr[3]; |
58 | } |
59 | |
60 | u_int16_t get2Bytes() { |
61 | ensureValidBytes(2); |
62 | |
63 | unsigned char const* ptr = nextToParse(); |
64 | u_int16_t result = (ptr[0]<<8)|ptr[1]; |
65 | |
66 | fCurParserIndex += 2; |
67 | fRemainingUnparsedBits = 0; |
68 | |
69 | return result; |
70 | } |
71 | u_int16_t test2Bytes() { |
72 | ensureValidBytes(2); |
73 | |
74 | unsigned char const* ptr = nextToParse(); |
75 | return (ptr[0]<<8)|ptr[1]; |
76 | } |
77 | |
78 | |
79 | u_int8_t get1Byte() { // byte-aligned |
80 | ensureValidBytes(1); |
81 | fRemainingUnparsedBits = 0; |
82 | return curBank()[fCurParserIndex++]; |
83 | } |
84 | u_int8_t test1Byte() { // as above, but doesn't advance ptr |
85 | ensureValidBytes(1); |
86 | return nextToParse()[0]; |
87 | } |
88 | |
89 | void getBytes(u_int8_t* to, unsigned numBytes) { |
90 | testBytes(to, numBytes); |
91 | fCurParserIndex += numBytes; |
92 | fRemainingUnparsedBits = 0; |
93 | } |
94 | void testBytes(u_int8_t* to, unsigned numBytes) { // as above, but doesn't advance ptr |
95 | ensureValidBytes(numBytes); |
96 | memmove(to, nextToParse(), numBytes); |
97 | } |
98 | void skipBytes(unsigned numBytes) { |
99 | ensureValidBytes(numBytes); |
100 | fCurParserIndex += numBytes; |
101 | } |
102 | |
103 | void skipBits(unsigned numBits); |
104 | unsigned getBits(unsigned numBits); |
105 | // numBits <= 32; returns data into low-order bits of result |
106 | |
107 | unsigned curOffset() const { return fCurParserIndex; } |
108 | |
109 | unsigned& totNumValidBytes() { return fTotNumValidBytes; } |
110 | |
111 | Boolean haveSeenEOF() const { return fHaveSeenEOF; } |
112 | |
113 | unsigned bankSize() const; |
114 | |
115 | private: |
116 | unsigned char* curBank() { return fCurBank; } |
117 | unsigned char* nextToParse() { return &curBank()[fCurParserIndex]; } |
118 | unsigned char* lastParsed() { return &curBank()[fCurParserIndex-1]; } |
119 | |
120 | // makes sure that at least "numBytes" valid bytes remain: |
121 | void ensureValidBytes(unsigned numBytesNeeded) { |
122 | // common case: inlined: |
123 | if (fCurParserIndex + numBytesNeeded <= fTotNumValidBytes) return; |
124 | |
125 | ensureValidBytes1(numBytesNeeded); |
126 | } |
127 | void ensureValidBytes1(unsigned numBytesNeeded); |
128 | |
129 | static void afterGettingBytes(void* clientData, unsigned numBytesRead, |
130 | unsigned numTruncatedBytes, |
131 | struct timeval presentationTime, |
132 | unsigned durationInMicroseconds); |
133 | void afterGettingBytes1(unsigned numBytesRead, struct timeval presentationTime); |
134 | |
135 | static void onInputClosure(void* clientData); |
136 | void onInputClosure1(); |
137 | |
138 | private: |
139 | FramedSource* fInputSource; // should be a byte-stream source?? |
140 | FramedSource::onCloseFunc* fClientOnInputCloseFunc; |
141 | void* fClientOnInputCloseClientData; |
142 | clientContinueFunc* fClientContinueFunc; |
143 | void* fClientContinueClientData; |
144 | |
145 | // Use a pair of 'banks', and swap between them as they fill up: |
146 | unsigned char* fBank[2]; |
147 | unsigned char fCurBankNum; |
148 | unsigned char* fCurBank; |
149 | |
150 | // The most recent 'saved' parse position: |
151 | unsigned fSavedParserIndex; // <= fCurParserIndex |
152 | unsigned char fSavedRemainingUnparsedBits; |
153 | |
154 | // The current position of the parser within the current bank: |
155 | unsigned fCurParserIndex; // <= fTotNumValidBytes |
156 | unsigned char fRemainingUnparsedBits; // in previous byte: [0,7] |
157 | |
158 | // The total number of valid bytes stored in the current bank: |
159 | unsigned fTotNumValidBytes; // <= BANK_SIZE |
160 | |
161 | // Whether we have seen EOF on the input source: |
162 | Boolean fHaveSeenEOF; |
163 | |
164 | struct timeval fLastSeenPresentationTime; // hack used for EOF handling |
165 | }; |
166 | |
167 | #endif |
168 | |