KiCad PCB EDA Suite
Loading...
Searching...
No Matches
bit_stream_writer.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 Mark Roszko <[email protected]>
3 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
4 * Copyright (C) 2007 Ecma International (original Java source)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * License info found here:
19 * https://www.loc.gov/preservation/digital/formats/fdd/fdd000491.shtml
20 */
21
22#include <cmath>
23#include <cstring>
24#include "bit_stream_writer.h"
25#include "constants.h"
26
27using namespace U3D;
28
30 m_contextManager( nullptr ),
31 m_high( 0x0000FFFF ),
32 m_low( 0 ),
33 m_underflow( 0 ),
34 m_compressed( false ),
35 m_data(),
36 m_dataPosition( 0 ),
37 m_dataLocal( 0 ),
38 m_dataLocalNext( 0 ),
40{
41 m_contextManager = std::make_unique<CONTEXT_MANAGER>();
42 m_data = std::vector<uint32_t>( m_dataSizeIncrement );
43}
44
45
46void BIT_STREAM_WRITER::WriteU8( uint8_t aValue )
47{
48 uint32_t symbol = (uint32_t) aValue;
49 swapBits8( symbol );
50 bool escape = false;
51 writeSymbol( CONSTANTS::Context8, symbol, escape );
52}
53
54
55void BIT_STREAM_WRITER::WriteU16( uint16_t uValue )
56{
57 WriteU8( (uint8_t) ( 0x00FF & uValue ) );
58 WriteU8( (uint8_t) ( 0x00FF & ( uValue >> 8 ) ) );
59}
60
61
62void BIT_STREAM_WRITER::WriteU32( uint32_t uValue )
63{
64 WriteU16( (uint16_t) ( 0x0000FFFF & uValue ) );
65 WriteU16( (uint16_t) ( 0x0000FFFF & ( uValue >> 16 ) ) );
66}
67
68
69void BIT_STREAM_WRITER::WriteU64( uint64_t uValue )
70{
71 WriteU32( (uint32_t) ( 0x00000000FFFFFFFF & uValue ) );
72 WriteU32( (uint32_t) ( 0x00000000FFFFFFFF & ( uValue >> 32 ) ) );
73}
74
75
76void BIT_STREAM_WRITER::WriteI32( int32_t iValue )
77{
78 WriteU32( (uint32_t) iValue );
79}
80
81
82void BIT_STREAM_WRITER::WriteF32( float fValue )
83{
84 uint32_t uValue;
85 std::memcpy( &uValue, &fValue, sizeof( fValue ) );
86 WriteU32( uValue );
87}
88
89
90void BIT_STREAM_WRITER::WriteF64( double aValue )
91{
92 uint64_t uValue;
93 std::memcpy( &uValue, &aValue, sizeof( aValue ) );
94 WriteU64( uValue );
95}
96
97
98void BIT_STREAM_WRITER::WriteCompressedU32( uint32_t aContext, uint32_t uValue )
99{
100 m_compressed = true;
101 bool escape = false;
102 if( ( aContext != 0 ) && ( aContext < CONSTANTS::MaxRange ) )
103 {
104 writeSymbol( aContext, uValue, escape );
105 if( escape == true )
106 {
107 WriteU32( uValue );
108 //Assuming symbol is a class member, and is in scope.
109 //If symbol is not in scope, you will have to find the correct
110 //symbol value to add to the context manager.
111 m_contextManager->AddSymbol( aContext, uValue + 1 );
112 }
113 }
114 else
115 {
116 WriteU32( uValue );
117 }
118}
119
120
121void BIT_STREAM_WRITER::WriteCompressedU16( uint32_t aContext, uint16_t uValue )
122{
123 m_compressed = true;
124 bool escape = false;
125 if( ( aContext != 0 ) && ( aContext < CONSTANTS::MaxRange ) )
126 {
127 writeSymbol( aContext, uValue, escape );
128 if( escape == true )
129 {
130 WriteU16( uValue );
131 //Assuming symbol is a class member, and is in scope.
132 //If symbol is not in scope, you will have to find the correct
133 //symbol value to add to the context manager.
134 m_contextManager->AddSymbol( aContext, uValue + 1 );
135 }
136 }
137 else
138 {
139 WriteU16( uValue );
140 }
141}
142
143
144void BIT_STREAM_WRITER::WriteCompressedU8( uint32_t aContext, uint8_t uValue )
145{
146 m_compressed = true;
147 bool escape = false;
148 if( ( aContext != 0 ) && ( aContext < CONSTANTS::MaxRange ) )
149 {
150 writeSymbol( aContext, uValue, escape );
151 if( escape == true )
152 {
153 WriteU8( uValue );
154 //Assuming symbol is a class member, and is in scope.
155 //If symbol is not in scope, you will have to find the correct
156 //symbol value to add to the context manager.
157 m_contextManager->AddSymbol( aContext, uValue + 1 );
158 }
159 }
160 else
161 {
162 WriteU8( uValue );
163 }
164}
165
166
167void BIT_STREAM_WRITER::WriteString( const std::string& aStr )
168{
169 WriteU16( (uint16_t) aStr.length() );
170
171 for( size_t i = 0; i < aStr.length(); i++ )
172 WriteU8( aStr[i] );
173}
174
175
177{
178 int32_t uBitCount = 0;
179 GetBitCount( uBitCount );
180
181 uBitCount = ( 8 - ( uBitCount & 7 ) ) & 7;
182 m_dataBitOffset += uBitCount;
183 if( m_dataBitOffset >= 32 )
184 {
185 m_dataBitOffset -= 32;
187 }
188}
189
190
192{
193 if( m_dataBitOffset > 0 )
194 {
195 m_dataBitOffset = 0;
197 }
198}
199
200void BIT_STREAM_WRITER::GetBitCount( int32_t& rCount )
201{
202 rCount = ( m_dataPosition << 5 ) + m_dataBitOffset;
203}
204
205
206void BIT_STREAM_WRITER::WriteDataBlock( std::shared_ptr<DATA_BLOCK> b )
207{
208 int dataSize = static_cast<int>( std::ceil( static_cast<double>( b->GetDataSize() ) / 4.0 ) );
209 int metaDataSize =
210 static_cast<int>( std::ceil( static_cast<double>( b->GetMetaDataSize() ) / 4.0 ) );
211
212 WriteU32( b->GetBlockType() );
213 WriteU32( b->GetDataSize() );
214 WriteU32( b->GetMetaDataSize() );
215
216 for( int i = 0; i < dataSize; i++ )
217 {
218 WriteU32( b->GetData()[i] );
219 }
220
221 for( int i = 0; i < metaDataSize; i++ )
222 {
223 WriteU32( b->GetMetaData()[i] );
224 }
225}
226
227
228std::shared_ptr<DATA_BLOCK> BIT_STREAM_WRITER::GetDataBlock()
229{
230 if( m_compressed )
231 {
232 WriteU32( 0 );
233 }
234 AlignToByte();
235 uint32_t numBytes = ( m_dataPosition << 2 ) + ( m_dataBitOffset >> 3 );
236 std::shared_ptr<DATA_BLOCK> ret = std::make_shared<DATA_BLOCK>();
237 putLocal();
238 ret->SetDataSize( numBytes );
239 ret->SetData( m_data );
240
241 return ret;
242}
243
244
250
251
252void BIT_STREAM_WRITER::writeSymbol( uint32_t aContext, uint32_t aSymbol, bool& rEscape )
253{
254 aSymbol++;
255 rEscape = false;
256 uint32_t totalCumFreq = 0;
257 uint32_t symbolCumFreq = 0;
258 uint32_t symbolFreq = 0;
259
260 totalCumFreq = m_contextManager->GetTotalSymbolFrequency( aContext );
261 symbolCumFreq = m_contextManager->GetCumulativeSymbolFrequency( aContext, aSymbol );
262 symbolFreq = m_contextManager->GetSymbolFrequency( aContext, aSymbol );
263
264 if( 0 == symbolFreq )
265 {
266 aSymbol = 0;
267 symbolCumFreq = m_contextManager->GetCumulativeSymbolFrequency( aContext, aSymbol );
268 symbolFreq = m_contextManager->GetSymbolFrequency( aContext, aSymbol );
269 }
270
271 if( 0 == aSymbol )
272 {
273 rEscape = true;
274 }
275
276 uint32_t range = m_high + 1 - m_low;
277 m_high = m_low - 1 + range * ( symbolCumFreq + symbolFreq ) / totalCumFreq;
278 m_low = m_low + range * symbolCumFreq / totalCumFreq;
279
280 m_contextManager->AddSymbol( aContext, aSymbol );
281
282
283 //write bits
284 uint32_t bit = m_low >> 15;
285
286 //uint32_t highmask = m_high & U3DConstants::HalfMask;
287 //uint32_t lowmask = m_low & U3DConstants::HalfMask;
288
290 {
291 m_high &= ~CONSTANTS::HalfMask;
292 m_high += m_high + 1;
293 writeBit( bit );
294 while( m_underflow > 0 )
295 {
296 m_underflow--;
297 writeBit( ( ~bit ) & 1 );
298 }
299 m_low &= ~CONSTANTS::HalfMask;
300 m_low += m_low;
301 bit = m_low >> 15;
302 }
303
304 //check for underflow
305 // Underflow occurs when the values stored in this.high and
306 // this.low differ only in the most significant bit.
307 // The precision of the variables is not large enough to predict
308 // the next symbol.
309 while( ( 0 == ( m_high & CONSTANTS::QuarterMask ) )
311 {
312 m_high &= ~CONSTANTS::HalfMask;
313 m_high <<= 1;
314 m_low <<= 1;
316 m_high |= 1;
317 m_low &= ~CONSTANTS::HalfMask;
318 m_underflow++;
319 }
320}
321
322
323void BIT_STREAM_WRITER::swapBits8( uint32_t& rValue )
324{
325 rValue = ( CONSTANTS::Swap8[( rValue ) & 0xf] << 4 ) | ( CONSTANTS::Swap8[( rValue ) >> 4] );
326}
327
328
329void BIT_STREAM_WRITER::writeBit( uint32_t aBit )
330{
331 uint32_t mask = 1;
332 aBit &= mask;
333 m_dataLocal &= ~( mask << m_dataBitOffset );
334 m_dataLocal |= ( aBit << m_dataBitOffset );
335 m_dataBitOffset += 1;
336 if( m_dataBitOffset >= 32 )
337 {
338 m_dataBitOffset -= 32;
340 }
341}
342
343
352
353
355{
356 if( static_cast<size_t>( m_dataPosition + 2 ) > m_data.size() )
357 {
359 }
360}
void WriteF64(double aValue)
void swapBits8(uint32_t &rValue)
changes the ordering of an 8 bit value so that the first 4 bits become the last 4 bits and the last 4...
void WriteU8(uint8_t aValue)
uint32_t m_underflow
stores the number of bits of underflow cause dby the limited range of high and low
void GetBitCount(int32_t &rCount)
Returns the number of bits written.
void WriteU16(uint16_t uValue)
void checkPosition()
Checks that the array allocated for writing is large enough.
void WriteI32(int32_t iValue)
void WriteU32(uint32_t uValue)
std::shared_ptr< DATA_BLOCK > GetDataBlock()
void WriteDataBlock(std::shared_ptr< DATA_BLOCK > b)
uint32_t m_high
high and low are the upper and lower limits on the probability
void WriteF32(float fValue)
void WriteString(const std::string &aStr)
void WriteCompressedU16(uint32_t aContext, uint16_t uValue)
std::vector< uint32_t > m_data
uint32_t m_dataLocalNext
The value of the data after m_dataLocal.
void writeSymbol(uint32_t aContext, uint32_t aSymbol, bool &rEscape)
std::unique_ptr< CONTEXT_MANAGER > m_contextManager
void incrementPosition()
Updates the values of the datablock stored in dataLocal and dataLocalNext to the next values in the d...
void WriteU64(uint64_t uValue)
uint32_t m_dataLocal
The local value of the data corresponding to m_dataPosition.
void WriteCompressedU32(uint32_t aContext, uint32_t uValue)
void writeBit(uint32_t aBit)
bool m_compressed
Indicates if a compressed value was written.
int32_t m_dataBitOffset
The offset into data local that the next write occur.
void WriteCompressedU8(uint32_t aContext, uint8_t uValue)
const int32_t m_dataSizeIncrement
static const uint32_t MaxRange
The largest allowable static context.
Definition constants.h:62
static const uint32_t Swap8[]
Definition constants.h:25
static const uint32_t Context8
Uncompressed U8 Context.
Definition constants.h:35
static const uint32_t HalfMask
Bit masks for reading and writing symbols.
Definition constants.h:41
static const uint32_t QuarterMask
Masks all but the 2nd most significan bit.
Definition constants.h:49