1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "oox/xls/biffoutputstream.hxx" 29 30 namespace oox { 31 namespace xls { 32 33 // ============================================================================ 34 35 namespace prv { 36 37 BiffOutputRecordBuffer::BiffOutputRecordBuffer( BinaryOutputStream& rOutStrm, sal_uInt16 nMaxRecSize ) : 38 mrOutStrm( rOutStrm ), 39 mnMaxRecSize( nMaxRecSize ), 40 mnRecId( BIFF_ID_UNKNOWN ), 41 mbInRec( false ) 42 { 43 OSL_ENSURE( mrOutStrm.isSeekable(), "BiffOutputRecordBuffer::BiffOutputRecordBuffer - stream must be seekable" ); 44 maData.reserve( SAL_MAX_UINT16 ); 45 } 46 47 void BiffOutputRecordBuffer::startRecord( sal_uInt16 nRecId ) 48 { 49 OSL_ENSURE( !mbInRec, "BiffOutputRecordBuffer::startRecord - another record still open" ); 50 mnRecId = nRecId; 51 maData.clear(); 52 mbInRec = true; 53 } 54 55 void BiffOutputRecordBuffer::endRecord() 56 { 57 OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::endRecord - no record open" ); 58 sal_uInt16 nRecSize = getLimitedValue< sal_uInt16, size_t >( maData.size(), 0, SAL_MAX_UINT16 ); 59 mrOutStrm.seekToEnd(); 60 mrOutStrm << mnRecId << nRecSize; 61 if( nRecSize > 0 ) 62 mrOutStrm.writeMemory( &maData.front(), nRecSize ); 63 mbInRec = false; 64 } 65 66 void BiffOutputRecordBuffer::write( const void* pData, sal_uInt16 nBytes ) 67 { 68 OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::write - no record open" ); 69 OSL_ENSURE( nBytes > 0, "BiffOutputRecordBuffer::write - nothing to write" ); 70 OSL_ENSURE( nBytes <= getRecLeft(), "BiffOutputRecordBuffer::write - buffer overflow" ); 71 maData.resize( maData.size() + nBytes ); 72 memcpy( &*(maData.end() - nBytes), pData, nBytes ); 73 } 74 75 void BiffOutputRecordBuffer::fill( sal_uInt8 nValue, sal_uInt16 nBytes ) 76 { 77 OSL_ENSURE( mbInRec, "BiffOutputRecordBuffer::write - no record open" ); 78 OSL_ENSURE( nBytes > 0, "BiffOutputRecordBuffer::write - nothing to write" ); 79 OSL_ENSURE( nBytes <= getRecLeft(), "BiffOutputRecordBuffer::write - buffer overflow" ); 80 maData.resize( maData.size() + nBytes, nValue ); 81 } 82 83 } // namespace prv 84 85 // ============================================================================ 86 87 BiffOutputStream::BiffOutputStream( BinaryOutputStream& rOutStream, sal_uInt16 nMaxRecSize ) : 88 BinaryStreamBase( true ), 89 maRecBuffer( rOutStream, nMaxRecSize ), 90 mnPortionSize( 0 ), 91 mnPortionPos( 0 ) 92 { 93 } 94 95 // record control ------------------------------------------------------------- 96 97 void BiffOutputStream::startRecord( sal_uInt16 nRecId ) 98 { 99 maRecBuffer.startRecord( nRecId ); 100 setPortionSize( 1 ); 101 } 102 103 void BiffOutputStream::endRecord() 104 { 105 setPortionSize( 1 ); 106 maRecBuffer.endRecord(); 107 } 108 109 void BiffOutputStream::setPortionSize( sal_uInt8 nSize ) 110 { 111 OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::setPortionSize - block operation inside portion" ); 112 mnPortionSize = ::std::max< sal_uInt8 >( nSize, 1 ); 113 mnPortionPos = 0; 114 } 115 116 // BinaryStreamBase interface (seeking) --------------------------------------- 117 118 sal_Int64 BiffOutputStream::tellBase() const 119 { 120 return maRecBuffer.getBaseStream().tell(); 121 } 122 123 sal_Int64 BiffOutputStream::sizeBase() const 124 { 125 return maRecBuffer.getBaseStream().size(); 126 } 127 128 // BinaryOutputStream interface (stream write access) ------------------------- 129 130 void BiffOutputStream::writeData( const StreamDataSequence& rData, size_t nAtomSize ) 131 { 132 if( rData.hasElements() ) 133 writeMemory( rData.getConstArray(), rData.getLength(), nAtomSize ); 134 } 135 136 void BiffOutputStream::writeMemory( const void* pMem, sal_Int32 nBytes, size_t nAtomSize ) 137 { 138 if( pMem && (nBytes > 0) ) 139 { 140 const sal_uInt8* pnBuffer = reinterpret_cast< const sal_uInt8* >( pMem ); 141 sal_Int32 nBytesLeft = nBytes; 142 while( nBytesLeft > 0 ) 143 { 144 sal_uInt16 nBlockSize = prepareWriteBlock( nBytesLeft, nAtomSize ); 145 maRecBuffer.write( pnBuffer, nBlockSize ); 146 pnBuffer += nBlockSize; 147 nBytesLeft -= nBlockSize; 148 } 149 } 150 } 151 152 void BiffOutputStream::fill( sal_uInt8 nValue, sal_Int32 nBytes, size_t nAtomSize ) 153 { 154 sal_Int32 nBytesLeft = nBytes; 155 while( nBytesLeft > 0 ) 156 { 157 sal_uInt16 nBlockSize = prepareWriteBlock( nBytesLeft, nAtomSize ); 158 maRecBuffer.fill( nValue, nBlockSize ); 159 nBytesLeft -= nBlockSize; 160 } 161 } 162 163 // private -------------------------------------------------------------------- 164 165 sal_uInt16 BiffOutputStream::prepareWriteBlock( sal_Int32 nTotalSize, size_t nAtomSize ) 166 { 167 sal_uInt16 nRecLeft = maRecBuffer.getRecLeft(); 168 if( mnPortionSize <= 1 ) 169 { 170 // no portions: restrict remaining record size to entire atoms 171 nRecLeft = static_cast< sal_uInt16 >( (nRecLeft / nAtomSize) * nAtomSize ); 172 } 173 else 174 { 175 sal_Int32 nPortionLeft = mnPortionSize - mnPortionPos; 176 if( nTotalSize <= nPortionLeft ) 177 { 178 // block fits into the current portion 179 OSL_ENSURE( nPortionLeft <= nRecLeft, "BiffOutputStream::prepareWriteBlock - portion exceeds record" ); 180 mnPortionPos = static_cast< sal_uInt8 >( (mnPortionPos + nTotalSize) % mnPortionSize ); 181 } 182 else 183 { 184 // restrict remaining record size to entire portions 185 OSL_ENSURE( mnPortionPos == 0, "BiffOutputStream::prepareWriteBlock - writing over multiple portions starts inside portion" ); 186 mnPortionPos = 0; 187 // check that atom size matches portion size 188 OSL_ENSURE( mnPortionSize % nAtomSize == 0, "BiffOutputStream::prepareWriteBlock - atom size does not match portion size" ); 189 sal_uInt8 nPortionSize = static_cast< sal_uInt8 >( (mnPortionSize / nAtomSize) * nAtomSize ); 190 // restrict remaining record size to entire portions 191 nRecLeft = (nRecLeft / nPortionSize) * nPortionSize; 192 } 193 } 194 195 // current record has space for some data: return size of available space 196 if( nRecLeft > 0 ) 197 return getLimitedValue< sal_uInt16, sal_Int32 >( nTotalSize, 0, nRecLeft ); 198 199 // finish current record and start a new CONTINUE record 200 maRecBuffer.endRecord(); 201 maRecBuffer.startRecord( BIFF_ID_CONT ); 202 mnPortionPos = 0; 203 return prepareWriteBlock( nTotalSize, nAtomSize ); 204 } 205 206 // ============================================================================ 207 208 } // namespace xls 209 } // namespace oox 210