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 .
21 #include <comphelper/string.hxx>
23 #include <rtl/strbuf.hxx>
24 #include <vcl/svapp.hxx>
25 #include <tools/urlobj.hxx>
26 #include <vcl/wrkwin.hxx>
27 #include <sot/formats.hxx>
29 #include <svl/urihelper.hxx>
30 #include <svtools/imap.hxx>
31 #include <svtools/imapobj.hxx>
32 #include <svtools/imaprect.hxx>
33 #include <svtools/imapcirc.hxx>
34 #include <svtools/imappoly.hxx>
38 #define NOTEOL(c) ((c)!='\0')
40 TYPEINIT0_AUTOFACTORY( ImageMap
);
42 void IMapObject::AppendCERNCoords(OStringBuffer
& rBuf
, const Point
& rPoint100
)
44 const Point
aPixPt( Application::GetDefaultDevice()->LogicToPixel( rPoint100
, MapMode( MAP_100TH_MM
) ) );
47 rBuf
.append(static_cast<sal_Int32
>(aPixPt
.X()));
49 rBuf
.append(static_cast<sal_Int32
>(aPixPt
.Y()));
53 void IMapObject::AppendNCSACoords(OStringBuffer
& rBuf
, const Point
& rPoint100
)
55 const Point
aPixPt( Application::GetDefaultDevice()->LogicToPixel( rPoint100
, MapMode( MAP_100TH_MM
) ) );
57 rBuf
.append(static_cast<sal_Int32
>(aPixPt
.X()));
59 rBuf
.append(static_cast<sal_Int32
>(aPixPt
.Y()));
63 void IMapObject::AppendCERNURL(OStringBuffer
& rBuf
, const OUString
& rBaseURL
) const
65 rBuf
.append(OUStringToOString(URIHelper::simpleNormalizedMakeRelative(rBaseURL
, aURL
), osl_getThreadTextEncoding()));
68 void IMapObject::AppendNCSAURL(OStringBuffer
& rBuf
, const OUString
& rBaseURL
) const
70 rBuf
.append(OUStringToOString(URIHelper::simpleNormalizedMakeRelative(rBaseURL
, aURL
), osl_getThreadTextEncoding()));
74 void IMapRectangleObject::WriteCERN( SvStream
& rOStm
, const OUString
& rBaseURL
) const
76 OStringBuffer
aStrBuf("rectangle ");
78 AppendCERNCoords(aStrBuf
, aRect
.TopLeft());
79 AppendCERNCoords(aStrBuf
, aRect
.BottomRight());
80 AppendCERNURL(aStrBuf
, rBaseURL
);
82 rOStm
.WriteLine(aStrBuf
.makeStringAndClear());
85 void IMapRectangleObject::WriteNCSA( SvStream
& rOStm
, const OUString
& rBaseURL
) const
87 OStringBuffer
aStrBuf("rect ");
89 AppendNCSAURL(aStrBuf
, rBaseURL
);
90 AppendNCSACoords(aStrBuf
, aRect
.TopLeft());
91 AppendNCSACoords(aStrBuf
, aRect
.BottomRight());
93 rOStm
.WriteLine(aStrBuf
.makeStringAndClear());
96 void IMapCircleObject::WriteCERN( SvStream
& rOStm
, const OUString
& rBaseURL
) const
98 OStringBuffer
aStrBuf("circle ");
100 AppendCERNCoords(aStrBuf
, aCenter
);
101 aStrBuf
.append(nRadius
);
103 AppendCERNURL(aStrBuf
, rBaseURL
);
105 rOStm
.WriteLine(aStrBuf
.makeStringAndClear());
108 void IMapCircleObject::WriteNCSA( SvStream
& rOStm
, const OUString
& rBaseURL
) const
110 OStringBuffer
aStrBuf("circle ");
112 AppendNCSAURL(aStrBuf
, rBaseURL
);
113 AppendNCSACoords(aStrBuf
, aCenter
);
114 AppendNCSACoords(aStrBuf
, aCenter
+ Point(nRadius
, 0));
116 rOStm
.WriteLine(aStrBuf
.makeStringAndClear());
119 void IMapPolygonObject::WriteCERN( SvStream
& rOStm
, const OUString
& rBaseURL
) const
121 OStringBuffer
aStrBuf("polygon ");
122 const sal_uInt16 nCount
= aPoly
.GetSize();
124 for (sal_uInt16 i
= 0; i
< nCount
; ++i
)
125 AppendCERNCoords(aStrBuf
, aPoly
[i
]);
127 AppendCERNURL(aStrBuf
, rBaseURL
);
129 rOStm
.WriteLine(aStrBuf
.makeStringAndClear());
132 void IMapPolygonObject::WriteNCSA( SvStream
& rOStm
, const OUString
& rBaseURL
) const
134 OStringBuffer
aStrBuf("poly ");
135 const sal_uInt16 nCount
= std::min( aPoly
.GetSize(), (sal_uInt16
) 100 );
137 AppendNCSAURL(aStrBuf
, rBaseURL
);
139 for (sal_uInt16 i
= 0; i
< nCount
; ++i
)
140 AppendNCSACoords(aStrBuf
, aPoly
[i
]);
142 rOStm
.WriteLine(aStrBuf
.makeStringAndClear());
145 void ImageMap::Write( SvStream
& rOStm
, sal_uLong nFormat
, const OUString
& rBaseURL
) const
149 case( IMAP_FORMAT_BIN
) : Write( rOStm
, rBaseURL
); break;
150 case( IMAP_FORMAT_CERN
) : ImpWriteCERN( rOStm
, rBaseURL
); break;
151 case( IMAP_FORMAT_NCSA
) : ImpWriteNCSA( rOStm
, rBaseURL
); break;
158 void ImageMap::ImpWriteCERN( SvStream
& rOStm
, const OUString
& rBaseURL
) const
160 size_t nCount
= maList
.size();
162 for ( size_t i
= 0; i
< nCount
; i
++ )
164 IMapObject
* pObj
= maList
[ i
];
166 switch( pObj
->GetType() )
168 case( IMAP_OBJ_RECTANGLE
):
169 static_cast<IMapRectangleObject
*>( pObj
)->WriteCERN( rOStm
, rBaseURL
);
172 case( IMAP_OBJ_CIRCLE
):
173 static_cast<IMapCircleObject
*>( pObj
)->WriteCERN( rOStm
, rBaseURL
);
176 case( IMAP_OBJ_POLYGON
):
177 static_cast<IMapPolygonObject
*>( pObj
)->WriteCERN( rOStm
, rBaseURL
);
186 void ImageMap::ImpWriteNCSA( SvStream
& rOStm
, const OUString
& rBaseURL
) const
188 size_t nCount
= maList
.size();
190 for ( size_t i
= 0; i
< nCount
; i
++ )
192 IMapObject
* pObj
= maList
[ i
];
194 switch( pObj
->GetType() )
196 case( IMAP_OBJ_RECTANGLE
):
197 static_cast<IMapRectangleObject
*>( pObj
)->WriteNCSA( rOStm
, rBaseURL
);
200 case( IMAP_OBJ_CIRCLE
):
201 static_cast<IMapCircleObject
*>( pObj
)->WriteNCSA( rOStm
, rBaseURL
);
204 case( IMAP_OBJ_POLYGON
):
205 static_cast<IMapPolygonObject
*>( pObj
)->WriteNCSA( rOStm
, rBaseURL
);
214 sal_uLong
ImageMap::Read( SvStream
& rIStm
, sal_uLong nFormat
, const OUString
& rBaseURL
)
216 sal_uLong nRet
= IMAP_ERR_FORMAT
;
218 if ( nFormat
== IMAP_FORMAT_DETECT
)
219 nFormat
= ImpDetectFormat( rIStm
);
223 case ( IMAP_FORMAT_BIN
) : Read( rIStm
, rBaseURL
); break;
224 case ( IMAP_FORMAT_CERN
) : nRet
= ImpReadCERN( rIStm
, rBaseURL
); break;
225 case ( IMAP_FORMAT_NCSA
) : nRet
= ImpReadNCSA( rIStm
, rBaseURL
); break;
231 if ( !rIStm
.GetError() )
237 sal_uLong
ImageMap::ImpReadCERN( SvStream
& rIStm
, const OUString
& rBaseURL
)
239 // delete old content
243 while ( rIStm
.ReadLine( aStr
) )
244 ImpReadCERNLine( aStr
, rBaseURL
);
249 void ImageMap::ImpReadCERNLine( const OString
& rLine
, const OUString
& rBaseURL
)
251 OString aStr
= comphelper::string::stripStart(rLine
, ' ');
252 aStr
= comphelper::string::stripStart(aStr
, '\t');
253 aStr
= comphelper::string::remove(aStr
, ';');
254 aStr
= aStr
.toAsciiLowerCase();
256 const char* pStr
= aStr
.getStr();
257 char cChar
= *pStr
++;
261 while( ( cChar
>= 'a' ) && ( cChar
<= 'z' ) && NOTEOL( cChar
) )
266 OString aToken
= aBuf
.makeStringAndClear();
268 if ( NOTEOL( cChar
) )
270 if ( ( aToken
== "rectangle" ) || ( aToken
== "rect" ) )
272 const Point
aTopLeft( ImpReadCERNCoords( &pStr
) );
273 const Point
aBottomRight( ImpReadCERNCoords( &pStr
) );
274 const OUString
aURL( ImpReadCERNURL( &pStr
, rBaseURL
) );
275 const Rectangle
aRect( aTopLeft
, aBottomRight
);
277 IMapRectangleObject
* pObj
= new IMapRectangleObject( aRect
, aURL
, OUString(), OUString(), OUString(), OUString() );
278 maList
.push_back( pObj
);
280 else if ( ( aToken
== "circle" ) || ( aToken
== "circ" ) )
282 const Point
aCenter( ImpReadCERNCoords( &pStr
) );
283 const long nRadius
= ImpReadCERNRadius( &pStr
);
284 const OUString
aURL( ImpReadCERNURL( &pStr
, rBaseURL
) );
286 IMapCircleObject
* pObj
= new IMapCircleObject( aCenter
, nRadius
, aURL
, OUString(), OUString(), OUString(), OUString() );
287 maList
.push_back( pObj
);
289 else if ( ( aToken
== "polygon" ) || ( aToken
== "poly" ) )
291 const sal_uInt16 nCount
= comphelper::string::getTokenCount(aStr
,
293 Polygon
aPoly( nCount
);
296 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
297 aPoly
[ i
] = ImpReadCERNCoords( &pStr
);
299 aURL
= ImpReadCERNURL( &pStr
, rBaseURL
);
301 IMapPolygonObject
* pObj
= new IMapPolygonObject( aPoly
, aURL
, OUString(), OUString(), OUString(), OUString() );
302 maList
.push_back( pObj
);
307 Point
ImageMap::ImpReadCERNCoords( const char** ppStr
)
309 OUStringBuffer aStrX
;
310 OUStringBuffer aStrY
;
312 char cChar
= *(*ppStr
)++;
314 while( NOTEOL( cChar
) && ( ( cChar
< '0' ) || ( cChar
> '9' ) ) )
317 if ( NOTEOL( cChar
) )
319 while( NOTEOL( cChar
) && ( cChar
>= '0' ) && ( cChar
<= '9' ) )
321 aStrX
.append( cChar
);
325 if ( NOTEOL( cChar
) )
327 while( NOTEOL( cChar
) && ( ( cChar
< '0' ) || ( cChar
> '9' ) ) )
330 while( NOTEOL( cChar
) && ( cChar
>= '0' ) && ( cChar
<= '9' ) )
332 aStrY
.append( cChar
);
336 if ( NOTEOL( cChar
) )
337 while( NOTEOL( cChar
) && ( cChar
!= ')' ) )
340 aPt
= Point( aStrX
.makeStringAndClear().toInt32(), aStrY
.makeStringAndClear().toInt32() );
347 long ImageMap::ImpReadCERNRadius( const char** ppStr
)
350 char cChar
= *(*ppStr
)++;
352 while( NOTEOL( cChar
) && ( ( cChar
< '0' ) || ( cChar
> '9' ) ) )
355 if ( NOTEOL( cChar
) )
357 while( NOTEOL( cChar
) && ( cChar
>= '0' ) && ( cChar
<= '9' ) )
359 aStr
.append( cChar
);
364 return aStr
.makeStringAndClear().toInt32();
367 OUString
ImageMap::ImpReadCERNURL( const char** ppStr
, const OUString
& rBaseURL
)
369 OUString
aStr(OUString::createFromAscii(*ppStr
));
371 aStr
= comphelper::string::stripStart(aStr
, ' ');
372 aStr
= comphelper::string::stripStart(aStr
, '\t');
373 aStr
= comphelper::string::stripEnd(aStr
, ' ');
374 aStr
= comphelper::string::stripEnd(aStr
, '\t');
376 return INetURLObject::GetAbsURL( rBaseURL
, aStr
);
379 sal_uLong
ImageMap::ImpReadNCSA( SvStream
& rIStm
, const OUString
& rBaseURL
)
381 // delete old content
385 while ( rIStm
.ReadLine( aStr
) )
386 ImpReadNCSALine( aStr
, rBaseURL
);
391 void ImageMap::ImpReadNCSALine( const OString
& rLine
, const OUString
& rBaseURL
)
393 OString aStr
= comphelper::string::stripStart(rLine
, ' ');
394 aStr
= comphelper::string::stripStart(aStr
, '\t');
395 aStr
= comphelper::string::remove(aStr
, ';');
396 aStr
= aStr
.toAsciiLowerCase();
398 const char* pStr
= aStr
.getStr();
399 char cChar
= *pStr
++;
403 while( ( cChar
>= 'a' ) && ( cChar
<= 'z' ) && NOTEOL( cChar
) )
408 OString aToken
= aBuf
.makeStringAndClear();
410 if ( NOTEOL( cChar
) )
412 if ( aToken
== "rect" )
414 const OUString
aURL( ImpReadNCSAURL( &pStr
, rBaseURL
) );
415 const Point
aTopLeft( ImpReadNCSACoords( &pStr
) );
416 const Point
aBottomRight( ImpReadNCSACoords( &pStr
) );
417 const Rectangle
aRect( aTopLeft
, aBottomRight
);
419 IMapRectangleObject
* pObj
= new IMapRectangleObject( aRect
, aURL
, OUString(), OUString(), OUString(), OUString() );
420 maList
.push_back( pObj
);
422 else if ( aToken
== "circle" )
424 const OUString
aURL( ImpReadNCSAURL( &pStr
, rBaseURL
) );
425 const Point
aCenter( ImpReadNCSACoords( &pStr
) );
426 const Point
aDX( aCenter
- ImpReadNCSACoords( &pStr
) );
427 long nRadius
= (long) sqrt( (double) aDX
.X() * aDX
.X() +
428 (double) aDX
.Y() * aDX
.Y() );
430 IMapCircleObject
* pObj
= new IMapCircleObject( aCenter
, nRadius
, aURL
, OUString(), OUString(), OUString(), OUString() );
431 maList
.push_back( pObj
);
433 else if ( aToken
== "poly" )
435 const sal_uInt16 nCount
= comphelper::string::getTokenCount(aStr
,
437 const OUString
aURL( ImpReadNCSAURL( &pStr
, rBaseURL
) );
438 Polygon
aPoly( nCount
);
440 for ( sal_uInt16 i
= 0; i
< nCount
; i
++ )
441 aPoly
[ i
] = ImpReadNCSACoords( &pStr
);
443 IMapPolygonObject
* pObj
= new IMapPolygonObject( aPoly
, aURL
, OUString(), OUString(), OUString(), OUString() );
444 maList
.push_back( pObj
);
449 OUString
ImageMap::ImpReadNCSAURL( const char** ppStr
, const OUString
& rBaseURL
)
452 char cChar
= *(*ppStr
)++;
454 while( NOTEOL( cChar
) && ( ( cChar
== ' ' ) || ( cChar
== '\t' ) ) )
457 if ( NOTEOL( cChar
) )
459 while( NOTEOL( cChar
) && ( cChar
!= ' ' ) && ( cChar
!= '\t' ) )
461 aStr
.append( cChar
);
466 return INetURLObject::GetAbsURL( rBaseURL
, aStr
.makeStringAndClear() );
469 Point
ImageMap::ImpReadNCSACoords( const char** ppStr
)
471 OUStringBuffer aStrX
;
472 OUStringBuffer aStrY
;
474 char cChar
= *(*ppStr
)++;
476 while( NOTEOL( cChar
) && ( ( cChar
< '0' ) || ( cChar
> '9' ) ) )
479 if ( NOTEOL( cChar
) )
481 while( NOTEOL( cChar
) && ( cChar
>= '0' ) && ( cChar
<= '9' ) )
483 aStrX
.append( cChar
);
487 if ( NOTEOL( cChar
) )
489 while( NOTEOL( cChar
) && ( ( cChar
< '0' ) || ( cChar
> '9' ) ) )
492 while( NOTEOL( cChar
) && ( cChar
>= '0' ) && ( cChar
<= '9' ) )
494 aStrY
.append( cChar
);
498 aPt
= Point( aStrX
.makeStringAndClear().toInt32(), aStrY
.makeStringAndClear().toInt32() );
505 sal_uLong
ImageMap::ImpDetectFormat( SvStream
& rIStm
)
507 sal_uLong nPos
= rIStm
.Tell();
508 sal_uLong nRet
= IMAP_FORMAT_BIN
;
511 rIStm
.Read( cMagic
, sizeof( cMagic
) );
513 // if we do not have an internal formats
514 // we check the format
515 if ( memcmp( cMagic
, IMAPMAGIC
, sizeof( cMagic
) ) )
521 while ( rIStm
.ReadLine( aStr
) && nCount
-- )
523 aStr
= aStr
.toAsciiLowerCase();
525 if ( (aStr
.indexOf("rect") != -1) ||
526 (aStr
.indexOf("circ") != -1) ||
527 (aStr
.indexOf("poly") != -1) )
529 if ( ( aStr
.indexOf('(') != -1 ) &&
530 ( aStr
.indexOf(')') != -1 ) )
532 nRet
= IMAP_FORMAT_CERN
;
535 nRet
= IMAP_FORMAT_NCSA
;
547 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */