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