1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski #include "oox/xls/biffoutputstream.hxx"
25*b1cdbd2cSJim Jagielski 
26*b1cdbd2cSJim Jagielski namespace oox {
27*b1cdbd2cSJim Jagielski namespace xls {
28*b1cdbd2cSJim Jagielski 
29*b1cdbd2cSJim Jagielski // ============================================================================
30*b1cdbd2cSJim Jagielski 
31*b1cdbd2cSJim Jagielski namespace prv {
32*b1cdbd2cSJim Jagielski 
BiffOutputRecordBuffer(BinaryOutputStream & rOutStrm,sal_uInt16 nMaxRecSize)33*b1cdbd2cSJim Jagielski BiffOutputRecordBuffer::BiffOutputRecordBuffer( BinaryOutputStream& rOutStrm, sal_uInt16 nMaxRecSize ) :
34*b1cdbd2cSJim Jagielski     mrOutStrm( rOutStrm ),
35*b1cdbd2cSJim Jagielski     mnMaxRecSize( nMaxRecSize ),
36*b1cdbd2cSJim Jagielski     mnRecId( BIFF_ID_UNKNOWN ),
37*b1cdbd2cSJim Jagielski     mbInRec( false )
38*b1cdbd2cSJim Jagielski {
39*b1cdbd2cSJim Jagielski     OSL_ENSURE( mrOutStrm.isSeekable(), "BiffOutputRecordBuffer::BiffOutputRecordBuffer - stream must be seekable" );
40*b1cdbd2cSJim Jagielski     maData.reserve( SAL_MAX_UINT16 );
41*b1cdbd2cSJim Jagielski }
42*b1cdbd2cSJim Jagielski 
startRecord(sal_uInt16 nRecId)43*b1cdbd2cSJim Jagielski void BiffOutputRecordBuffer::startRecord( sal_uInt16 nRecId )
44*b1cdbd2cSJim Jagielski {
45*b1cdbd2cSJim Jagielski     OSL_ENSURE( !mbInRec, "BiffOutputRecordBuffer::startRecord - another record still open" );
46*b1cdbd2cSJim Jagielski     mnRecId = nRecId;
47*b1cdbd2cSJim Jagielski     maData.clear();
48*b1cdbd2cSJim Jagielski     mbInRec = true;
49*b1cdbd2cSJim Jagielski }
50*b1cdbd2cSJim Jagielski 
endRecord()51*b1cdbd2cSJim Jagielski void BiffOutputRecordBuffer::endRecord()
52*b1cdbd2cSJim Jagielski {
53*b1cdbd2cSJim Jagielski     OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::endRecord - no record open" );
54*b1cdbd2cSJim Jagielski     sal_uInt16 nRecSize = getLimitedValue< sal_uInt16, size_t >( maData.size(), 0, SAL_MAX_UINT16 );
55*b1cdbd2cSJim Jagielski     mrOutStrm.seekToEnd();
56*b1cdbd2cSJim Jagielski     mrOutStrm << mnRecId << nRecSize;
57*b1cdbd2cSJim Jagielski     if( nRecSize > 0 )
58*b1cdbd2cSJim Jagielski         mrOutStrm.writeMemory( &maData.front(), nRecSize );
59*b1cdbd2cSJim Jagielski     mbInRec = false;
60*b1cdbd2cSJim Jagielski }
61*b1cdbd2cSJim Jagielski 
write(const void * pData,sal_uInt16 nBytes)62*b1cdbd2cSJim Jagielski void BiffOutputRecordBuffer::write( const void* pData, sal_uInt16 nBytes )
63*b1cdbd2cSJim Jagielski {
64*b1cdbd2cSJim Jagielski     OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::write - no record open" );
65*b1cdbd2cSJim Jagielski     OSL_ENSURE( nBytes > 0, "BiffOutputRecordBuffer::write - nothing to write" );
66*b1cdbd2cSJim Jagielski     OSL_ENSURE( nBytes <= getRecLeft(), "BiffOutputRecordBuffer::write - buffer overflow" );
67*b1cdbd2cSJim Jagielski     maData.resize( maData.size() + nBytes );
68*b1cdbd2cSJim Jagielski     memcpy( &*(maData.end() - nBytes), pData, nBytes );
69*b1cdbd2cSJim Jagielski }
70*b1cdbd2cSJim Jagielski 
fill(sal_uInt8 nValue,sal_uInt16 nBytes)71*b1cdbd2cSJim Jagielski void BiffOutputRecordBuffer::fill( sal_uInt8 nValue, sal_uInt16 nBytes )
72*b1cdbd2cSJim Jagielski {
73*b1cdbd2cSJim Jagielski     OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::write - no record open" );
74*b1cdbd2cSJim Jagielski     OSL_ENSURE( nBytes > 0, "BiffOutputRecordBuffer::write - nothing to write" );
75*b1cdbd2cSJim Jagielski     OSL_ENSURE( nBytes <= getRecLeft(), "BiffOutputRecordBuffer::write - buffer overflow" );
76*b1cdbd2cSJim Jagielski     maData.resize( maData.size() + nBytes, nValue );
77*b1cdbd2cSJim Jagielski }
78*b1cdbd2cSJim Jagielski 
79*b1cdbd2cSJim Jagielski } // namespace prv
80*b1cdbd2cSJim Jagielski 
81*b1cdbd2cSJim Jagielski // ============================================================================
82*b1cdbd2cSJim Jagielski 
BiffOutputStream(BinaryOutputStream & rOutStream,sal_uInt16 nMaxRecSize)83*b1cdbd2cSJim Jagielski BiffOutputStream::BiffOutputStream( BinaryOutputStream& rOutStream, sal_uInt16 nMaxRecSize ) :
84*b1cdbd2cSJim Jagielski     BinaryStreamBase( true ),
85*b1cdbd2cSJim Jagielski     maRecBuffer( rOutStream, nMaxRecSize ),
86*b1cdbd2cSJim Jagielski     mnPortionSize( 0 ),
87*b1cdbd2cSJim Jagielski     mnPortionPos( 0 )
88*b1cdbd2cSJim Jagielski {
89*b1cdbd2cSJim Jagielski }
90*b1cdbd2cSJim Jagielski 
91*b1cdbd2cSJim Jagielski // record control -------------------------------------------------------------
92*b1cdbd2cSJim Jagielski 
startRecord(sal_uInt16 nRecId)93*b1cdbd2cSJim Jagielski void BiffOutputStream::startRecord( sal_uInt16 nRecId )
94*b1cdbd2cSJim Jagielski {
95*b1cdbd2cSJim Jagielski     maRecBuffer.startRecord( nRecId );
96*b1cdbd2cSJim Jagielski     setPortionSize( 1 );
97*b1cdbd2cSJim Jagielski }
98*b1cdbd2cSJim Jagielski 
endRecord()99*b1cdbd2cSJim Jagielski void BiffOutputStream::endRecord()
100*b1cdbd2cSJim Jagielski {
101*b1cdbd2cSJim Jagielski     setPortionSize( 1 );
102*b1cdbd2cSJim Jagielski     maRecBuffer.endRecord();
103*b1cdbd2cSJim Jagielski }
104*b1cdbd2cSJim Jagielski 
setPortionSize(sal_uInt8 nSize)105*b1cdbd2cSJim Jagielski void BiffOutputStream::setPortionSize( sal_uInt8 nSize )
106*b1cdbd2cSJim Jagielski {
107*b1cdbd2cSJim Jagielski     OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::setPortionSize - block operation inside portion" );
108*b1cdbd2cSJim Jagielski     mnPortionSize = ::std::max< sal_uInt8 >( nSize, 1 );
109*b1cdbd2cSJim Jagielski     mnPortionPos = 0;
110*b1cdbd2cSJim Jagielski }
111*b1cdbd2cSJim Jagielski 
112*b1cdbd2cSJim Jagielski // BinaryStreamBase interface (seeking) ---------------------------------------
113*b1cdbd2cSJim Jagielski 
tellBase() const114*b1cdbd2cSJim Jagielski sal_Int64 BiffOutputStream::tellBase() const
115*b1cdbd2cSJim Jagielski {
116*b1cdbd2cSJim Jagielski     return maRecBuffer.getBaseStream().tell();
117*b1cdbd2cSJim Jagielski }
118*b1cdbd2cSJim Jagielski 
sizeBase() const119*b1cdbd2cSJim Jagielski sal_Int64 BiffOutputStream::sizeBase() const
120*b1cdbd2cSJim Jagielski {
121*b1cdbd2cSJim Jagielski     return maRecBuffer.getBaseStream().size();
122*b1cdbd2cSJim Jagielski }
123*b1cdbd2cSJim Jagielski 
124*b1cdbd2cSJim Jagielski // BinaryOutputStream interface (stream write access) -------------------------
125*b1cdbd2cSJim Jagielski 
writeData(const StreamDataSequence & rData,size_t nAtomSize)126*b1cdbd2cSJim Jagielski void BiffOutputStream::writeData( const StreamDataSequence& rData, size_t nAtomSize )
127*b1cdbd2cSJim Jagielski {
128*b1cdbd2cSJim Jagielski     if( rData.hasElements() )
129*b1cdbd2cSJim Jagielski         writeMemory( rData.getConstArray(), rData.getLength(), nAtomSize );
130*b1cdbd2cSJim Jagielski }
131*b1cdbd2cSJim Jagielski 
writeMemory(const void * pMem,sal_Int32 nBytes,size_t nAtomSize)132*b1cdbd2cSJim Jagielski void BiffOutputStream::writeMemory( const void* pMem, sal_Int32 nBytes, size_t nAtomSize )
133*b1cdbd2cSJim Jagielski {
134*b1cdbd2cSJim Jagielski     if( pMem && (nBytes > 0) )
135*b1cdbd2cSJim Jagielski     {
136*b1cdbd2cSJim Jagielski         const sal_uInt8* pnBuffer = reinterpret_cast< const sal_uInt8* >( pMem );
137*b1cdbd2cSJim Jagielski         sal_Int32 nBytesLeft = nBytes;
138*b1cdbd2cSJim Jagielski         while( nBytesLeft > 0 )
139*b1cdbd2cSJim Jagielski         {
140*b1cdbd2cSJim Jagielski             sal_uInt16 nBlockSize = prepareWriteBlock( nBytesLeft, nAtomSize );
141*b1cdbd2cSJim Jagielski             maRecBuffer.write( pnBuffer, nBlockSize );
142*b1cdbd2cSJim Jagielski             pnBuffer += nBlockSize;
143*b1cdbd2cSJim Jagielski             nBytesLeft -= nBlockSize;
144*b1cdbd2cSJim Jagielski         }
145*b1cdbd2cSJim Jagielski     }
146*b1cdbd2cSJim Jagielski }
147*b1cdbd2cSJim Jagielski 
fill(sal_uInt8 nValue,sal_Int32 nBytes,size_t nAtomSize)148*b1cdbd2cSJim Jagielski void BiffOutputStream::fill( sal_uInt8 nValue, sal_Int32 nBytes, size_t nAtomSize )
149*b1cdbd2cSJim Jagielski {
150*b1cdbd2cSJim Jagielski     sal_Int32 nBytesLeft = nBytes;
151*b1cdbd2cSJim Jagielski     while( nBytesLeft > 0 )
152*b1cdbd2cSJim Jagielski     {
153*b1cdbd2cSJim Jagielski         sal_uInt16 nBlockSize = prepareWriteBlock( nBytesLeft, nAtomSize );
154*b1cdbd2cSJim Jagielski         maRecBuffer.fill( nValue, nBlockSize );
155*b1cdbd2cSJim Jagielski         nBytesLeft -= nBlockSize;
156*b1cdbd2cSJim Jagielski     }
157*b1cdbd2cSJim Jagielski }
158*b1cdbd2cSJim Jagielski 
159*b1cdbd2cSJim Jagielski // private --------------------------------------------------------------------
160*b1cdbd2cSJim Jagielski 
prepareWriteBlock(sal_Int32 nTotalSize,size_t nAtomSize)161*b1cdbd2cSJim Jagielski sal_uInt16 BiffOutputStream::prepareWriteBlock( sal_Int32 nTotalSize, size_t nAtomSize )
162*b1cdbd2cSJim Jagielski {
163*b1cdbd2cSJim Jagielski     sal_uInt16 nRecLeft = maRecBuffer.getRecLeft();
164*b1cdbd2cSJim Jagielski     if( mnPortionSize <= 1 )
165*b1cdbd2cSJim Jagielski     {
166*b1cdbd2cSJim Jagielski         // no portions: restrict remaining record size to entire atoms
167*b1cdbd2cSJim Jagielski         nRecLeft = static_cast< sal_uInt16 >( (nRecLeft / nAtomSize) * nAtomSize );
168*b1cdbd2cSJim Jagielski     }
169*b1cdbd2cSJim Jagielski     else
170*b1cdbd2cSJim Jagielski     {
171*b1cdbd2cSJim Jagielski         sal_Int32 nPortionLeft = mnPortionSize - mnPortionPos;
172*b1cdbd2cSJim Jagielski         if( nTotalSize <= nPortionLeft )
173*b1cdbd2cSJim Jagielski         {
174*b1cdbd2cSJim Jagielski             // block fits into the current portion
175*b1cdbd2cSJim Jagielski             OSL_ENSURE( nPortionLeft <= nRecLeft, "BiffOutputStream::prepareWriteBlock - portion exceeds record" );
176*b1cdbd2cSJim Jagielski             mnPortionPos = static_cast< sal_uInt8 >( (mnPortionPos + nTotalSize) % mnPortionSize );
177*b1cdbd2cSJim Jagielski         }
178*b1cdbd2cSJim Jagielski         else
179*b1cdbd2cSJim Jagielski         {
180*b1cdbd2cSJim Jagielski             // restrict remaining record size to entire portions
181*b1cdbd2cSJim Jagielski             OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::prepareWriteBlock - writing over multiple portions starts inside portion" );
182*b1cdbd2cSJim Jagielski             mnPortionPos = 0;
183*b1cdbd2cSJim Jagielski             // check that atom size matches portion size
184*b1cdbd2cSJim Jagielski             OSL_ENSURE( mnPortionSize % nAtomSize == 0, "BiffOutputStream::prepareWriteBlock - atom size does not match portion size" );
185*b1cdbd2cSJim Jagielski             sal_uInt8 nPortionSize = static_cast< sal_uInt8 >( (mnPortionSize / nAtomSize) * nAtomSize );
186*b1cdbd2cSJim Jagielski             // restrict remaining record size to entire portions
187*b1cdbd2cSJim Jagielski             nRecLeft = (nRecLeft / nPortionSize) * nPortionSize;
188*b1cdbd2cSJim Jagielski         }
189*b1cdbd2cSJim Jagielski     }
190*b1cdbd2cSJim Jagielski 
191*b1cdbd2cSJim Jagielski     // current record has space for some data: return size of available space
192*b1cdbd2cSJim Jagielski     if( nRecLeft > 0 )
193*b1cdbd2cSJim Jagielski         return getLimitedValue< sal_uInt16, sal_Int32 >( nTotalSize, 0, nRecLeft );
194*b1cdbd2cSJim Jagielski 
195*b1cdbd2cSJim Jagielski     // finish current record and start a new CONTINUE record
196*b1cdbd2cSJim Jagielski     maRecBuffer.endRecord();
197*b1cdbd2cSJim Jagielski     maRecBuffer.startRecord( BIFF_ID_CONT );
198*b1cdbd2cSJim Jagielski     mnPortionPos = 0;
199*b1cdbd2cSJim Jagielski     return prepareWriteBlock( nTotalSize, nAtomSize );
200*b1cdbd2cSJim Jagielski }
201*b1cdbd2cSJim Jagielski 
202*b1cdbd2cSJim Jagielski // ============================================================================
203*b1cdbd2cSJim Jagielski 
204*b1cdbd2cSJim Jagielski } // namespace xls
205*b1cdbd2cSJim Jagielski } // namespace oox
206