LibreOffice Module vcl (master)  1
imap2.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
21 #include <comphelper/string.hxx>
22 #include <string.h>
23 #include <rtl/strbuf.hxx>
24 #include <vcl/outdev.hxx>
25 #include <vcl/svapp.hxx>
26 #include <tools/urlobj.hxx>
27 
28 #include <svl/urihelper.hxx>
29 #include <vcl/imap.hxx>
30 #include <vcl/imapobj.hxx>
31 #include <vcl/imaprect.hxx>
32 #include <vcl/imapcirc.hxx>
33 #include <vcl/imappoly.hxx>
34 
35 #include <math.h>
36 
37 #define NOTEOL(c) ((c)!='\0')
38 
39 void IMapObject::AppendCERNCoords(OStringBuffer& rBuf, const Point& rPoint100)
40 {
41  const Point aPixPt( Application::GetDefaultDevice()->LogicToPixel( rPoint100, MapMode( MapUnit::Map100thMM ) ) );
42 
43  rBuf.append('(');
44  rBuf.append(static_cast<sal_Int32>(aPixPt.X()));
45  rBuf.append(',');
46  rBuf.append(static_cast<sal_Int32>(aPixPt.Y()));
47  rBuf.append(") ");
48 }
49 
50 void IMapObject::AppendNCSACoords(OStringBuffer& rBuf, const Point& rPoint100)
51 {
52  const Point aPixPt( Application::GetDefaultDevice()->LogicToPixel( rPoint100, MapMode( MapUnit::Map100thMM ) ) );
53 
54  rBuf.append(static_cast<sal_Int32>(aPixPt.X()));
55  rBuf.append(',');
56  rBuf.append(static_cast<sal_Int32>(aPixPt.Y()));
57  rBuf.append(' ');
58 }
59 
60 void IMapObject::AppendCERNURL(OStringBuffer& rBuf) const
61 {
62  rBuf.append(OUStringToOString(URIHelper::simpleNormalizedMakeRelative("", aURL), osl_getThreadTextEncoding()));
63 }
64 
65 void IMapObject::AppendNCSAURL(OStringBuffer& rBuf) const
66 {
67  rBuf.append(OUStringToOString(URIHelper::simpleNormalizedMakeRelative("", aURL), osl_getThreadTextEncoding()));
68  rBuf.append(' ');
69 }
70 
72 {
73  OStringBuffer aStrBuf("rectangle ");
74 
75  AppendCERNCoords(aStrBuf, aRect.TopLeft());
77  AppendCERNURL(aStrBuf);
78 
79  rOStm.WriteLine(aStrBuf.makeStringAndClear());
80 }
81 
83 {
84  OStringBuffer aStrBuf("rect ");
85 
86  AppendNCSAURL(aStrBuf);
87  AppendNCSACoords(aStrBuf, aRect.TopLeft());
89 
90  rOStm.WriteLine(aStrBuf.makeStringAndClear());
91 }
92 
94 {
95  OStringBuffer aStrBuf("circle ");
96 
97  AppendCERNCoords(aStrBuf, aCenter);
98  aStrBuf.append(nRadius);
99  aStrBuf.append(' ');
100  AppendCERNURL(aStrBuf);
101 
102  rOStm.WriteLine(aStrBuf.makeStringAndClear());
103 }
104 
106 {
107  OStringBuffer aStrBuf("circle ");
108 
109  AppendNCSAURL(aStrBuf);
110  AppendNCSACoords(aStrBuf, aCenter);
111  AppendNCSACoords(aStrBuf, aCenter + Point(nRadius, 0));
112 
113  rOStm.WriteLine(aStrBuf.makeStringAndClear());
114 }
115 
117 {
118  OStringBuffer aStrBuf("polygon ");
119  const sal_uInt16 nCount = aPoly.GetSize();
120 
121  for (sal_uInt16 i = 0; i < nCount; ++i)
122  AppendCERNCoords(aStrBuf, aPoly[i]);
123 
124  AppendCERNURL(aStrBuf);
125 
126  rOStm.WriteLine(aStrBuf.makeStringAndClear());
127 }
128 
130 {
131  OStringBuffer aStrBuf("poly ");
132  const sal_uInt16 nCount = std::min( aPoly.GetSize(), sal_uInt16(100) );
133 
134  AppendNCSAURL(aStrBuf);
135 
136  for (sal_uInt16 i = 0; i < nCount; ++i)
137  AppendNCSACoords(aStrBuf, aPoly[i]);
138 
139  rOStm.WriteLine(aStrBuf.makeStringAndClear());
140 }
141 
142 void ImageMap::Write( SvStream& rOStm, sal_uLong nFormat ) const
143 {
144  switch( nFormat )
145  {
146  case IMAP_FORMAT_BIN : Write( rOStm ); break;
147  case IMAP_FORMAT_CERN : ImpWriteCERN( rOStm ); break;
148  case IMAP_FORMAT_NCSA : ImpWriteNCSA( rOStm ); break;
149 
150  default:
151  break;
152  }
153 }
154 
155 void ImageMap::ImpWriteCERN( SvStream& rOStm ) const
156 {
157  size_t nCount = maList.size();
158 
159  for ( size_t i = 0; i < nCount; i++ )
160  {
161  IMapObject* pObj = maList[ i ].get();
162 
163  switch( pObj->GetType() )
164  {
165  case IMAP_OBJ_RECTANGLE:
166  static_cast<IMapRectangleObject*>( pObj )->WriteCERN( rOStm );
167  break;
168 
169  case IMAP_OBJ_CIRCLE:
170  static_cast<IMapCircleObject*>( pObj )->WriteCERN( rOStm );
171  break;
172 
173  case IMAP_OBJ_POLYGON:
174  static_cast<IMapPolygonObject*>( pObj )->WriteCERN( rOStm );
175  break;
176 
177  default:
178  break;
179  }
180  }
181 }
182 
183 void ImageMap::ImpWriteNCSA( SvStream& rOStm ) const
184 {
185  size_t nCount = maList.size();
186 
187  for ( size_t i = 0; i < nCount; i++ )
188  {
189  IMapObject* pObj = maList[ i ].get();
190 
191  switch( pObj->GetType() )
192  {
193  case IMAP_OBJ_RECTANGLE:
194  static_cast<IMapRectangleObject*>( pObj )->WriteNCSA( rOStm );
195  break;
196 
197  case IMAP_OBJ_CIRCLE:
198  static_cast<IMapCircleObject*>( pObj )->WriteNCSA( rOStm );
199  break;
200 
201  case IMAP_OBJ_POLYGON:
202  static_cast<IMapPolygonObject*>( pObj )->WriteNCSA( rOStm );
203  break;
204 
205  default:
206  break;
207  }
208  }
209 }
210 
212 {
213  sal_uLong nRet = IMAP_ERR_FORMAT;
214 
215  if ( nFormat == IMAP_FORMAT_DETECT )
216  nFormat = ImpDetectFormat( rIStm );
217 
218  switch ( nFormat )
219  {
220  case IMAP_FORMAT_BIN : Read( rIStm ); break;
221  case IMAP_FORMAT_CERN : ImpReadCERN( rIStm ); break;
222  case IMAP_FORMAT_NCSA : ImpReadNCSA( rIStm ); break;
223 
224  default:
225  break;
226  }
227 
228  if ( !rIStm.GetError() )
229  nRet = IMAP_ERR_OK;
230 
231  return nRet;
232 }
233 
235 {
236  // delete old content
237  ClearImageMap();
238 
239  OString aStr;
240  while ( rIStm.ReadLine( aStr ) )
241  ImpReadCERNLine( aStr );
242 }
243 
244 void ImageMap::ImpReadCERNLine( const OString& rLine )
245 {
246  OString aStr = comphelper::string::stripStart(rLine, ' ');
247  aStr = comphelper::string::stripStart(aStr, '\t');
248  aStr = aStr.replaceAll(";", "");
249  aStr = aStr.toAsciiLowerCase();
250 
251  const char* pStr = aStr.getStr();
252  char cChar = *pStr++;
253 
254  // find instruction
255  OStringBuffer aBuf;
256  while ((cChar >= 'a') && (cChar <= 'z'))
257  {
258  aBuf.append(cChar);
259  cChar = *pStr++;
260  }
261  OString aToken = aBuf.makeStringAndClear();
262 
263  if ( !(NOTEOL( cChar )) )
264  return;
265 
266  if ( ( aToken == "rectangle" ) || ( aToken == "rect" ) )
267  {
268  const Point aTopLeft( ImpReadCERNCoords( &pStr ) );
269  const Point aBottomRight( ImpReadCERNCoords( &pStr ) );
270  const OUString aURL( ImpReadCERNURL( &pStr ) );
271  const tools::Rectangle aRect( aTopLeft, aBottomRight );
272 
273  maList.emplace_back( new IMapRectangleObject( aRect, aURL, OUString(), OUString(), OUString(), OUString() ) );
274  }
275  else if ( ( aToken == "circle" ) || ( aToken == "circ" ) )
276  {
277  const Point aCenter( ImpReadCERNCoords( &pStr ) );
278  const long nRadius = ImpReadCERNRadius( &pStr );
279  const OUString aURL( ImpReadCERNURL( &pStr ) );
280 
281  maList.emplace_back( new IMapCircleObject( aCenter, nRadius, aURL, OUString(), OUString(), OUString(), OUString() ) );
282  }
283  else if ( ( aToken == "polygon" ) || ( aToken == "poly" ) )
284  {
285  const sal_uInt16 nCount = comphelper::string::getTokenCount(aStr, '(') - 1;
286  tools::Polygon aPoly( nCount );
287 
288  for ( sal_uInt16 i = 0; i < nCount; i++ )
289  aPoly[ i ] = ImpReadCERNCoords( &pStr );
290 
291  const OUString aURL = ImpReadCERNURL( &pStr );
292 
293  maList.emplace_back( new IMapPolygonObject( aPoly, aURL, OUString(), OUString(), OUString(), OUString() ) );
294  }
295 }
296 
297 Point ImageMap::ImpReadCERNCoords( const char** ppStr )
298 {
299  OUStringBuffer aStrX;
300  OUStringBuffer aStrY;
301  Point aPt;
302  char cChar = *(*ppStr)++;
303 
304  while( NOTEOL( cChar ) && ( ( cChar < '0' ) || ( cChar > '9' ) ) )
305  cChar = *(*ppStr)++;
306 
307  if ( NOTEOL( cChar ) )
308  {
309  while( NOTEOL( cChar ) && ( cChar >= '0' ) && ( cChar <= '9' ) )
310  {
311  aStrX.append( cChar );
312  cChar = *(*ppStr)++;
313  }
314 
315  if ( NOTEOL( cChar ) )
316  {
317  while( NOTEOL( cChar ) && ( ( cChar < '0' ) || ( cChar > '9' ) ) )
318  cChar = *(*ppStr)++;
319 
320  while( NOTEOL( cChar ) && ( cChar >= '0' ) && ( cChar <= '9' ) )
321  {
322  aStrY.append( cChar );
323  cChar = *(*ppStr)++;
324  }
325 
326  if ( NOTEOL( cChar ) )
327  while( NOTEOL( cChar ) && ( cChar != ')' ) )
328  cChar = *(*ppStr)++;
329 
330  aPt = Point( aStrX.makeStringAndClear().toInt32(), aStrY.makeStringAndClear().toInt32() );
331  }
332  }
333 
334  return aPt;
335 }
336 
337 long ImageMap::ImpReadCERNRadius( const char** ppStr )
338 {
339  OUStringBuffer aStr;
340  char cChar = *(*ppStr)++;
341 
342  while( NOTEOL( cChar ) && ( ( cChar < '0' ) || ( cChar > '9' ) ) )
343  cChar = *(*ppStr)++;
344 
345  if ( NOTEOL( cChar ) )
346  {
347  while( NOTEOL( cChar ) && ( cChar >= '0' ) && ( cChar <= '9' ) )
348  {
349  aStr.append( cChar );
350  cChar = *(*ppStr)++;
351  }
352  }
353 
354  return aStr.makeStringAndClear().toInt32();
355 }
356 
357 OUString ImageMap::ImpReadCERNURL( const char** ppStr )
358 {
359  OUString aStr(OUString::createFromAscii(*ppStr));
360 
361  aStr = comphelper::string::stripStart(aStr, ' ');
362  aStr = comphelper::string::stripStart(aStr, '\t');
363  aStr = comphelper::string::stripEnd(aStr, ' ');
364  aStr = comphelper::string::stripEnd(aStr, '\t');
365 
366  return INetURLObject::GetAbsURL( "", aStr );
367 }
368 
370 {
371  // delete old content
372  ClearImageMap();
373 
374  OString aStr;
375  while ( rIStm.ReadLine( aStr ) )
376  ImpReadNCSALine( aStr );
377 }
378 
379 void ImageMap::ImpReadNCSALine( const OString& rLine )
380 {
381  OString aStr = comphelper::string::stripStart(rLine, ' ');
382  aStr = comphelper::string::stripStart(aStr, '\t');
383  aStr = aStr.replaceAll(";", "");
384  aStr = aStr.toAsciiLowerCase();
385 
386  const char* pStr = aStr.getStr();
387  char cChar = *pStr++;
388 
389  // find instruction
390  OStringBuffer aBuf;
391  while ((cChar >= 'a') && (cChar <= 'z'))
392  {
393  aBuf.append(cChar);
394  cChar = *pStr++;
395  }
396  OString aToken = aBuf.makeStringAndClear();
397 
398  if ( !(NOTEOL( cChar )) )
399  return;
400 
401  if ( aToken == "rect" )
402  {
403  const OUString aURL( ImpReadNCSAURL( &pStr ) );
404  const Point aTopLeft( ImpReadNCSACoords( &pStr ) );
405  const Point aBottomRight( ImpReadNCSACoords( &pStr ) );
406  const tools::Rectangle aRect( aTopLeft, aBottomRight );
407 
408  maList.emplace_back( new IMapRectangleObject( aRect, aURL, OUString(), OUString(), OUString(), OUString() ) );
409  }
410  else if ( aToken == "circle" )
411  {
412  const OUString aURL( ImpReadNCSAURL( &pStr ) );
413  const Point aCenter( ImpReadNCSACoords( &pStr ) );
414  const Point aDX( aCenter - ImpReadNCSACoords( &pStr ) );
415  long nRadius = static_cast<long>(sqrt( static_cast<double>(aDX.X()) * aDX.X() +
416  static_cast<double>(aDX.Y()) * aDX.Y() ));
417 
418  maList.emplace_back( new IMapCircleObject( aCenter, nRadius, aURL, OUString(), OUString(), OUString(), OUString() ) );
419  }
420  else if ( aToken == "poly" )
421  {
422  const sal_uInt16 nCount = comphelper::string::getTokenCount(aStr, ',') - 1;
423  const OUString aURL( ImpReadNCSAURL( &pStr ) );
424  tools::Polygon aPoly( nCount );
425 
426  for ( sal_uInt16 i = 0; i < nCount; i++ )
427  aPoly[ i ] = ImpReadNCSACoords( &pStr );
428 
429  maList.emplace_back( new IMapPolygonObject( aPoly, aURL, OUString(), OUString(), OUString(), OUString() ) );
430  }
431 }
432 
433 OUString ImageMap::ImpReadNCSAURL( const char** ppStr )
434 {
435  OUStringBuffer aStr;
436  char cChar = *(*ppStr)++;
437 
438  while( NOTEOL( cChar ) && ( ( cChar == ' ' ) || ( cChar == '\t' ) ) )
439  cChar = *(*ppStr)++;
440 
441  if ( NOTEOL( cChar ) )
442  {
443  while( NOTEOL( cChar ) && ( cChar != ' ' ) && ( cChar != '\t' ) )
444  {
445  aStr.append( cChar );
446  cChar = *(*ppStr)++;
447  }
448  }
449 
450  return INetURLObject::GetAbsURL( "", aStr.makeStringAndClear() );
451 }
452 
453 Point ImageMap::ImpReadNCSACoords( const char** ppStr )
454 {
455  OUStringBuffer aStrX;
456  OUStringBuffer aStrY;
457  Point aPt;
458  char cChar = *(*ppStr)++;
459 
460  while( NOTEOL( cChar ) && ( ( cChar < '0' ) || ( cChar > '9' ) ) )
461  cChar = *(*ppStr)++;
462 
463  if ( NOTEOL( cChar ) )
464  {
465  while( NOTEOL( cChar ) && ( cChar >= '0' ) && ( cChar <= '9' ) )
466  {
467  aStrX.append( cChar );
468  cChar = *(*ppStr)++;
469  }
470 
471  if ( NOTEOL( cChar ) )
472  {
473  while( NOTEOL( cChar ) && ( ( cChar < '0' ) || ( cChar > '9' ) ) )
474  cChar = *(*ppStr)++;
475 
476  while( NOTEOL( cChar ) && ( cChar >= '0' ) && ( cChar <= '9' ) )
477  {
478  aStrY.append( cChar );
479  cChar = *(*ppStr)++;
480  }
481 
482  aPt = Point( aStrX.makeStringAndClear().toInt32(), aStrY.makeStringAndClear().toInt32() );
483  }
484  }
485 
486  return aPt;
487 }
488 
490 {
491  sal_uInt64 nPos = rIStm.Tell();
492  sal_uLong nRet = IMAP_FORMAT_BIN;
493  char cMagic[6];
494 
495  rIStm.ReadBytes(cMagic, sizeof(cMagic));
496 
497  // if we do not have an internal formats
498  // we check the format
499  if ( memcmp( cMagic, IMAPMAGIC, sizeof( cMagic ) ) )
500  {
501  long nCount = 128;
502 
503  rIStm.Seek( nPos );
504  OString aStr;
505  while ( rIStm.ReadLine( aStr ) && nCount-- )
506  {
507  aStr = aStr.toAsciiLowerCase();
508 
509  if ( (aStr.indexOf("rect") != -1) ||
510  (aStr.indexOf("circ") != -1) ||
511  (aStr.indexOf("poly") != -1) )
512  {
513  if ( ( aStr.indexOf('(') != -1 ) &&
514  ( aStr.indexOf(')') != -1 ) )
515  {
516  nRet = IMAP_FORMAT_CERN;
517  }
518  else
519  nRet = IMAP_FORMAT_NCSA;
520 
521  break;
522  }
523  }
524  }
525 
526  rIStm.Seek( nPos );
527 
528  return nRet;
529 }
530 
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString aURL
Definition: imapobj.hxx:54
Point TopLeft() const
static Point ImpReadCERNCoords(const char **ppStr)
Definition: imap2.cxx:297
tools::Rectangle aRect
Definition: imaprect.hxx:30
void ImpWriteNCSA(SvStream &rOStm) const
Definition: imap2.cxx:183
OString stripEnd(const OString &rIn, sal_Char c)
void Write(SvStream &rOStm) const
Definition: imap.cxx:919
sal_Int32 nRadius
Definition: imapcirc.hxx:32
sal_uIntPtr sal_uLong
#define IMAP_OBJ_RECTANGLE
Definition: imapobj.hxx:30
aBuf
#define NOTEOL(c)
Definition: imap2.cxx:37
virtual sal_uInt16 GetType() const =0
sal_uInt64 Seek(sal_uInt64 nPos)
tools::Polygon aPoly
Definition: imappoly.hxx:31
#define IMAPMAGIC
Definition: imapobj.hxx:37
SVL_DLLPUBLIC OUString simpleNormalizedMakeRelative(OUString const &baseUriReference, OUString const &uriReference)
#define IMAP_FORMAT_BIN
Definition: imapobj.hxx:42
std::vector< std::unique_ptr< IMapObject > > maList
Definition: imap.hxx:39
static OutputDevice * GetDefaultDevice()
Get the default "device" (in this case the default window).
Definition: svapp.cxx:1054
void WriteCERN(SvStream &rOStm) const
Definition: imap2.cxx:71
void AppendNCSAURL(OStringBuffer &rBuf) const
Definition: imap2.cxx:65
static Point ImpReadNCSACoords(const char **ppStr)
Definition: imap2.cxx:453
ErrCode GetError() const
bool ReadLine(OString &rStr, sal_Int32 nMaxBytesToRead=0xFFFE)
static OUString GetAbsURL(OUString const &rTheBaseURIRef, OUString const &rTheRelURIRef, EncodeMechanism eEncodeMechanism=EncodeMechanism::WasEncoded, DecodeMechanism eDecodeMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
#define IMAP_OBJ_POLYGON
Definition: imapobj.hxx:32
void ImpReadNCSA(SvStream &rOStm)
Definition: imap2.cxx:369
static void AppendNCSACoords(OStringBuffer &rBuf, const Point &rPoint100)
Definition: imap2.cxx:50
Point BottomRight() const
#define IMAP_FORMAT_DETECT
Definition: imapobj.hxx:45
bool WriteLine(const OString &rStr)
static void AppendCERNCoords(OStringBuffer &rBuf, const Point &rPoint100)
Definition: imap2.cxx:39
int i
void ImpWriteCERN(SvStream &rOStm) const
Definition: imap2.cxx:155
OString stripStart(const OString &rIn, sal_Char c)
static long ImpReadCERNRadius(const char **ppStr)
Definition: imap2.cxx:337
static sal_uLong ImpDetectFormat(SvStream &rIStm)
Definition: imap2.cxx:489
sal_uInt16 GetSize() const
long X() const
#define IMAP_FORMAT_NCSA
Definition: imapobj.hxx:44
std::size_t ReadBytes(void *pData, std::size_t nSize)
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
static OUString ImpReadCERNURL(const char **ppStr)
Definition: imap2.cxx:357
void WriteNCSA(SvStream &rOStm) const
Definition: imap2.cxx:82
#define IMAP_ERR_OK
Definition: imapobj.hxx:47
void Read(SvStream &rIStm)
Definition: imap.cxx:955
void WriteNCSA(SvStream &rOStm) const
Definition: imap2.cxx:129
static OUString ImpReadNCSAURL(const char **ppStr)
Definition: imap2.cxx:433
sal_uInt64 Tell() const
void ImpReadNCSALine(const OString &rLine)
Definition: imap2.cxx:379
void WriteCERN(SvStream &rOStm) const
Definition: imap2.cxx:93
void WriteNCSA(SvStream &rOStm) const
Definition: imap2.cxx:105
#define IMAP_OBJ_CIRCLE
Definition: imapobj.hxx:31
sal_Int32 getTokenCount(const OString &rIn, sal_Char cTok)
void ImpReadCERNLine(const OString &rLine)
Definition: imap2.cxx:244
#define IMAP_ERR_FORMAT
Definition: imapobj.hxx:48
void AppendCERNURL(OStringBuffer &rBuf) const
Definition: imap2.cxx:60
void WriteCERN(SvStream &rOStm) const
Definition: imap2.cxx:116
sal_Int32 nPos
#define IMAP_FORMAT_CERN
Definition: imapobj.hxx:43
aStr
void ClearImageMap()
Definition: imap.cxx:614
long Y() const
void ImpReadCERN(SvStream &rOStm)
Definition: imap2.cxx:234