1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <propread.hxx>
21 #include "rtl/tencinfo.h"
22 #include "rtl/textenc.h"
24 PropEntry::PropEntry( sal_uInt32 nId
, const sal_uInt8
* pBuf
, sal_uInt32 nBufSize
, sal_uInt16 nTextEnc
) :
27 mnTextEnc ( nTextEnc
),
28 mpBuf ( new sal_uInt8
[ nBufSize
] )
30 memcpy( (void*)mpBuf
, (void*)pBuf
, nBufSize
);
33 PropEntry::PropEntry( const PropEntry
& rProp
) :
35 mnSize ( rProp
.mnSize
),
36 mnTextEnc ( rProp
.mnTextEnc
),
37 mpBuf ( new sal_uInt8
[ mnSize
] )
39 memcpy( (void*)mpBuf
, (void*)rProp
.mpBuf
, mnSize
);
42 PropEntry
& PropEntry::operator=(const PropEntry
& rPropEntry
)
44 if ( this != &rPropEntry
)
47 mnId
= rPropEntry
.mnId
;
48 mnSize
= rPropEntry
.mnSize
;
49 mnTextEnc
= rPropEntry
.mnTextEnc
;
50 mpBuf
= new sal_uInt8
[ mnSize
];
51 memcpy( (void*)mpBuf
, (void*)rPropEntry
.mpBuf
, mnSize
);
56 // -----------------------------------------------------------------------
58 void PropItem::Clear()
60 Seek( STREAM_SEEK_TO_BEGIN
);
61 delete[] (sal_uInt8
*)SwitchBuffer();
64 // -----------------------------------------------------------------------
66 static xub_StrLen
lcl_getMaxSafeStrLen(sal_uInt32 nSize
)
68 nSize
-= 1; //Drop NULL terminator
70 //If it won't fit in a string, clip it to the max size that does
71 if (nSize
> STRING_MAXLEN
)
72 nSize
= STRING_MAXLEN
;
74 return static_cast< xub_StrLen
>( nSize
);
77 sal_Bool
PropItem::Read( OUString
& rString
, sal_uInt32 nStringType
, sal_Bool bAlign
)
79 sal_uInt32 i
, nItemSize
, nType
, nItemPos
;
80 sal_Bool bRetValue
= sal_False
;
84 if ( nStringType
== VT_EMPTY
)
87 nType
= nStringType
& VT_TYPEMASK
;
99 sal_Char
* pString
= new sal_Char
[ nItemSize
];
100 if ( mnTextEnc
== RTL_TEXTENCODING_UCS2
)
105 sal_Unicode
* pWString
= (sal_Unicode
*)pString
;
106 for ( i
= 0; i
< nItemSize
; i
++ )
107 *this >> pWString
[ i
];
108 rString
= OUString(pWString
, lcl_getMaxSafeStrLen(nItemSize
));
111 rString
= OUString();
112 bRetValue
= sal_True
;
116 SvMemoryStream::Read( pString
, nItemSize
);
117 if ( pString
[ nItemSize
- 1 ] == 0 )
120 rString
= OUString(pString
, rtl_str_getLength(pString
), mnTextEnc
);
122 rString
= OUString();
123 bRetValue
= sal_True
;
128 catch( const std::bad_alloc
& )
130 OSL_FAIL( "sd PropItem::Read bad alloc" );
134 SeekRel( ( 4 - ( nItemSize
& 3 ) ) & 3 ); // dword align
144 sal_Unicode
* pString
= new sal_Unicode
[ nItemSize
];
145 for ( i
= 0; i
< nItemSize
; i
++ )
146 *this >> pString
[ i
];
147 if ( pString
[ i
- 1 ] == 0 )
149 if ( (sal_uInt16
)nItemSize
> 1 )
150 rString
= OUString(pString
, lcl_getMaxSafeStrLen(nItemSize
));
152 rString
= OUString();
153 bRetValue
= sal_True
;
157 catch( const std::bad_alloc
& )
159 OSL_FAIL( "sd PropItem::Read bad alloc" );
162 if ( bAlign
&& ( nItemSize
& 1 ) )
163 SeekRel( 2 ); // dword align
172 // -----------------------------------------------------------------------
174 PropItem
& PropItem::operator=( PropItem
& rPropItem
)
176 if ( this != &rPropItem
)
178 Seek( STREAM_SEEK_TO_BEGIN
);
179 delete[] (sal_uInt8
*)SwitchBuffer();
181 mnTextEnc
= rPropItem
.mnTextEnc
;
182 sal_uInt32 nItemPos
= rPropItem
.Tell();
183 rPropItem
.Seek( STREAM_SEEK_TO_END
);
184 SvMemoryStream::Write( rPropItem
.GetData(), rPropItem
.Tell() );
185 rPropItem
.Seek( nItemPos
);
190 // -----------------------------------------------------------------------
192 Section::Section( const Section
& rSection
)
193 : mnTextEnc(rSection
.mnTextEnc
),
194 maEntries(rSection
.maEntries
.clone())
196 for ( int i
= 0; i
< 16; i
++ )
197 aFMTID
[ i
] = rSection
.aFMTID
[ i
];
200 // -----------------------------------------------------------------------
202 Section::Section( const sal_uInt8
* pFMTID
)
204 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
205 for ( int i
= 0; i
< 16; i
++ )
206 aFMTID
[ i
] = pFMTID
[ i
];
209 // -----------------------------------------------------------------------
211 sal_Bool
Section::GetProperty( sal_uInt32 nId
, PropItem
& rPropItem
)
215 boost::ptr_vector
<PropEntry
>::const_iterator iter
;
216 for (iter
= maEntries
.begin(); iter
!= maEntries
.end(); ++iter
)
218 if (iter
->mnId
== nId
)
222 if (iter
!= maEntries
.end())
225 rPropItem
.SetTextEncoding( mnTextEnc
);
226 rPropItem
.Write( iter
->mpBuf
,iter
->mnSize
);
227 rPropItem
.Seek( STREAM_SEEK_TO_BEGIN
);
234 // -----------------------------------------------------------------------
236 void Section::AddProperty( sal_uInt32 nId
, const sal_uInt8
* pBuf
, sal_uInt32 nBufSize
)
238 // just a simple id check
242 if ( nId
== 0xffffffff )
245 // do not allow same PropId's, sort
246 boost::ptr_vector
<PropEntry
>::iterator iter
;
247 for ( iter
= maEntries
.begin(); iter
!= maEntries
.end(); ++iter
)
249 if ( iter
->mnId
== nId
)
250 maEntries
.replace( iter
, new PropEntry( nId
, pBuf
, nBufSize
, mnTextEnc
));
251 else if ( iter
->mnId
> nId
)
252 maEntries
.insert( iter
, new PropEntry( nId
, pBuf
, nBufSize
, mnTextEnc
));
258 maEntries
.push_back( new PropEntry( nId
, pBuf
, nBufSize
, mnTextEnc
) );
261 // -----------------------------------------------------------------------
263 sal_Bool
Section::GetDictionary( Dictionary
& rDict
)
265 sal_Bool bRetValue
= sal_False
;
267 boost::ptr_vector
<PropEntry
>::iterator iter
;
268 for (iter
= maEntries
.begin(); iter
!= maEntries
.end(); ++iter
)
270 if ( iter
->mnId
== 0 )
274 if ( iter
!= maEntries
.end() )
276 sal_uInt32 nDictCount
, nId
, nSize
, nPos
;
277 SvMemoryStream
aStream( (sal_Int8
*)iter
->mpBuf
, iter
->mnSize
, STREAM_READ
);
278 aStream
.Seek( STREAM_SEEK_TO_BEGIN
);
279 aStream
>> nDictCount
;
280 for ( sal_uInt32 i
= 0; i
< nDictCount
; i
++ )
282 aStream
>> nId
>> nSize
;
286 nPos
= aStream
.Tell();
289 sal_Char
* pString
= new sal_Char
[ nSize
];
290 aStream
.Read( pString
, nSize
);
291 if ( mnTextEnc
== RTL_TEXTENCODING_UCS2
)
294 aStream
.Seek( nPos
);
295 sal_Unicode
* pWString
= (sal_Unicode
*)pString
;
296 for ( i
= 0; i
< nSize
; i
++ )
297 aStream
>> pWString
[ i
];
298 aString
= OUString(pWString
, lcl_getMaxSafeStrLen(nSize
));
301 aString
= OUString(pString
, lcl_getMaxSafeStrLen(nSize
), mnTextEnc
);
304 catch( const std::bad_alloc
& )
306 OSL_FAIL( "sd Section::GetDictionary bad alloc" );
308 if ( !aString
.Len() )
310 rDict
.insert( std::make_pair(aString
,nId
) );
312 bRetValue
= sal_True
;
318 // -----------------------------------------------------------------------
320 void Section::Read( SvStorageStream
*pStrm
)
322 sal_uInt32 i
, nSecOfs
, nSecSize
, nPropCount
, nPropId
, nPropOfs
, nPropType
, nPropSize
, nCurrent
, nVectorCount
, nTemp
, nStrmSize
;
323 nSecOfs
= pStrm
->Tell();
325 pStrm
->Seek( STREAM_SEEK_TO_END
);
326 nStrmSize
= pStrm
->Tell();
327 pStrm
->Seek( nSecOfs
);
329 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
330 *pStrm
>> nSecSize
>> nPropCount
;
331 while( nPropCount
-- && ( pStrm
->GetError() == ERRCODE_NONE
) )
333 *pStrm
>> nPropId
>> nPropOfs
;
334 nCurrent
= pStrm
->Tell();
335 pStrm
->Seek( nPropOfs
+ nSecOfs
);
336 if ( nPropId
) // do not read dictionary
343 if ( nPropType
& VT_VECTOR
)
345 *pStrm
>> nVectorCount
;
346 nPropType
&=~VT_VECTOR
;
353 sal_Bool bVariant
= ( nPropType
== VT_VARIANT
);
355 for ( i
= 0; nPropSize
&& ( i
< nVectorCount
); i
++ )
392 nPropSize
+= ( nTemp
+ 4 );
397 nPropSize
+= ( nTemp
+ 4 );
403 // looks like these are aligned to 4 bytes
404 sal_uInt32 nLength
= nPropOfs
+ nSecOfs
+ nPropSize
+ ( nTemp
<< 1 ) + 4;
405 nPropSize
+= ( nTemp
<< 1 ) + 4 + (nLength
% 4);
409 case VT_BLOB_OBJECT
:
413 nPropSize
+= ( nTemp
+ 4 );
419 case VT_STREAMED_OBJECT
:
420 case VT_STORED_OBJECT
:
428 if ( ( nVectorCount
- i
) > 1 )
429 pStrm
->Seek( nPropOfs
+ nSecOfs
+ nPropSize
);
436 if ( nPropSize
> nStrmSize
)
441 pStrm
->Seek( nPropOfs
+ nSecOfs
);
442 // make sure we don't overflow the section size
443 if( nPropSize
> nSecSize
- nSecOfs
)
444 nPropSize
= nSecSize
- nSecOfs
;
445 sal_uInt8
* pBuf
= new sal_uInt8
[ nPropSize
];
446 pStrm
->Read( pBuf
, nPropSize
);
447 AddProperty( nPropId
, pBuf
, nPropSize
);
453 if ( GetProperty( 1, aPropItem
) )
455 sal_uInt16 nCodePage
;
456 aPropItem
>> nPropType
;
457 if ( nPropType
== VT_I2
)
459 aPropItem
>> nCodePage
;
461 if ( nCodePage
== 1200 )
463 mnTextEnc
= RTL_TEXTENCODING_UCS2
;
467 mnTextEnc
= rtl_getTextEncodingFromWindowsCodePage( nCodePage
);
468 if ( mnTextEnc
== RTL_TEXTENCODING_DONTKNOW
)
469 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
474 mnTextEnc
= RTL_TEXTENCODING_MS_1252
;
481 sal_uInt32 nDictCount
, nSize
;
482 *pStrm
>> nDictCount
;
483 for ( i
= 0; i
< nDictCount
; i
++ )
485 *pStrm
>> nSize
>> nSize
;
486 pStrm
->SeekRel( nSize
);
488 nSize
= pStrm
->Tell();
489 pStrm
->Seek( nPropOfs
+ nSecOfs
);
490 nSize
-= pStrm
->Tell();
491 if ( nSize
> nStrmSize
)
496 sal_uInt8
* pBuf
= new sal_uInt8
[ nSize
];
497 pStrm
->Read( pBuf
, nSize
);
498 AddProperty( 0xffffffff, pBuf
, nSize
);
501 pStrm
->Seek( nCurrent
);
503 pStrm
->Seek( nSecOfs
+ nSecSize
);
506 // -----------------------------------------------------------------------
508 Section
& Section::operator=( const Section
& rSection
)
510 if ( this != &rSection
)
512 memcpy( (void*)aFMTID
, (void*)rSection
.aFMTID
, 16 );
514 maEntries
= rSection
.maEntries
.clone();
519 // -----------------------------------------------------------------------
521 PropRead::PropRead( SvStorage
& rStorage
, const String
& rName
) :
522 mbStatus ( sal_False
),
523 mnByteOrder ( 0xfffe ),
528 if ( rStorage
.IsStream( rName
) )
530 mpSvStream
= rStorage
.OpenSotStream( rName
, STREAM_STD_READ
);
533 mpSvStream
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
534 memset( mApplicationCLSID
, 0, 16 );
540 // -----------------------------------------------------------------------
542 void PropRead::AddSection( Section
& rSection
)
544 maSections
.push_back( new Section( rSection
) );
547 // -----------------------------------------------------------------------
549 const Section
* PropRead::GetSection( const sal_uInt8
* pFMTID
)
551 boost::ptr_vector
<Section
>::iterator it
;
552 for ( it
= maSections
.begin(); it
!= maSections
.end(); ++it
)
554 if ( memcmp( it
->GetFMTID(), pFMTID
, 16 ) == 0 )
560 // -----------------------------------------------------------------------
562 void PropRead::Read()
568 sal_uInt32 nSections
;
569 sal_uInt32 nSectionOfs
;
571 *mpSvStream
>> mnByteOrder
>> mnFormat
>> mnVersionLo
>> mnVersionHi
;
572 if ( mnByteOrder
== 0xfffe )
574 sal_uInt8
* pSectCLSID
= new sal_uInt8
[ 16 ];
575 mpSvStream
->Read( mApplicationCLSID
, 16 );
576 *mpSvStream
>> nSections
;
577 if ( nSections
> 2 ) // sj: PowerPoint documents are containing max 2 sections
579 mbStatus
= sal_False
;
581 else for ( sal_uInt32 i
= 0; i
< nSections
; i
++ )
583 mpSvStream
->Read( pSectCLSID
, 16 );
584 *mpSvStream
>> nSectionOfs
;
585 nCurrent
= mpSvStream
->Tell();
586 mpSvStream
->Seek( nSectionOfs
);
587 Section
aSection( pSectCLSID
);
588 aSection
.Read( mpSvStream
);
589 AddSection( aSection
);
590 mpSvStream
->Seek( nCurrent
);
597 // -----------------------------------------------------------------------
599 PropRead
& PropRead::operator=( const PropRead
& rPropRead
)
601 if ( this != &rPropRead
)
603 mbStatus
= rPropRead
.mbStatus
;
604 mpSvStream
= rPropRead
.mpSvStream
;
606 mnByteOrder
= rPropRead
.mnByteOrder
;
607 mnFormat
= rPropRead
.mnFormat
;
608 mnVersionLo
= rPropRead
.mnVersionLo
;
609 mnVersionHi
= rPropRead
.mnVersionHi
;
610 memcpy( mApplicationCLSID
, rPropRead
.mApplicationCLSID
, 16 );
612 maSections
= rPropRead
.maSections
.clone();
617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */