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