1414 * *
1515 ***************************************************************************/
1616
17- #include < math.h> // needed for win32 build (ts)
17+ #include < cmath>
18+ #include < limits>
1819
1920#include < QString>
2021#include < QFont>
4546static const char * const ident_ =
4647 " $Id$" ;
4748
48-
4949QgsLabel::QgsLabel ( const QgsFieldMap & fields )
5050{
51-
5251 mField = fields;
5352 mLabelFieldIdx .resize ( LabelFieldCount );
5453 for ( int i = 0 ; i < LabelFieldCount; i++ )
@@ -459,8 +458,8 @@ void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature & feature
459458{
460459 QgsGeometry* geometry = feature.geometry ();
461460 unsigned char *geom = geometry->wkbBuffer ();
461+ size_t geomlen = geometry->wkbSize ();
462462 QGis::WKBTYPE wkbType = geometry->wkbType ();
463-
464463 QgsPoint point;
465464
466465 switch (wkbType)
@@ -472,10 +471,11 @@ void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature & feature
472471 case QGis::WKBPolygon25D:
473472 case QGis::WKBPolygon:
474473 {
475- labelPoint (point, geom);
474+ labelPoint (point, geom, geomlen );
476475 points.push_back (point);
477476 }
478477 break ;
478+
479479 case QGis::WKBMultiPoint25D:
480480 case QGis::WKBMultiPoint:
481481 case QGis::WKBMultiLineString25D:
@@ -484,11 +484,15 @@ void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature & feature
484484 case QGis::WKBMultiPolygon:
485485 // Return a position for each individual in the multi-feature
486486 {
487- int numFeatures = (int )(*(geom + 5 ));
488- geom += 9 ; // now points to start of array of WKB's
489- for (int i = 0 ; i < numFeatures; ++i)
487+ assert ( 1 +sizeof (wkbType)+sizeof (int )<=geomlen );
488+ geom += 1 +sizeof (wkbType);
489+ int nFeatures = *(unsigned int *)geom;
490+ geom += sizeof (int );
491+
492+ unsigned char *feature = geom;
493+ for (int i = 0 ; i<nFeatures && feature; ++i)
490494 {
491- geom = labelPoint (point, geom);
495+ feature = labelPoint (point, feature, geom+geomlen-feature );
492496 points.push_back (point);
493497 }
494498 }
@@ -498,156 +502,126 @@ void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature & feature
498502 }
499503}
500504
501- unsigned char * QgsLabel::labelPoint ( QgsPoint& point, unsigned char * geom)
505+ unsigned char * QgsLabel::labelPoint ( QgsPoint& point, unsigned char * geom, size_t geomlen )
502506{
503- // Number of bytes that ints and doubles take in the WKB format.
504- static const unsigned int sizeOfInt = 4 ;
505- static const unsigned int sizeOfDouble = 8 ;
507+ // verify that local types match sizes as WKB spec
508+ assert ( sizeof (int ) == 4 );
509+ assert ( sizeof (QGis::WKBTYPE) == 4 );
510+ assert ( sizeof (double ) == 8 );
511+
512+ if (geom==NULL ) {
513+ QgsDebugMsg (" empty wkb" );
514+ return NULL ;
515+ }
516+
517+ QGis::WKBTYPE wkbType;
518+ unsigned char *geomend = geom+geomlen;
506519
507- QGis::WKBTYPE wkbType;
508- bool hasZValue = false ;
509- double *x, *y;
510- unsigned char *ptr;
511- int *nPoints;
512- // Upon return from this function, this variable will contain a
513- // pointer to the first byte beyond the current feature.
514- unsigned char *nextFeature = geom;
520+ assert ( geom+1 +sizeof (wkbType)<=geomend );
515521
516- memcpy (&wkbType, (geom+1 ), sizeof (wkbType));
522+ geom++; // skip endianess
523+ memcpy (&wkbType, geom, sizeof (wkbType));
524+ geom += sizeof (wkbType);
517525
518- switch (wkbType)
526+ int dims = 2 ;
527+
528+ switch (wkbType)
529+ {
530+ case QGis::WKBPoint25D:
531+ case QGis::WKBPoint:
519532 {
520- case QGis::WKBPoint25D:
521- case QGis::WKBPoint:
533+ assert ( geom+2 *sizeof (double )<=geomend );
534+ double *pts = (double *)geom;
535+ point.set ( pts[0 ], pts[1 ] );
536+ geom += 2 *sizeof (double );
537+ }
538+ break ;
539+
540+ case QGis::WKBLineString25D:
541+ dims=3 ;
542+ case QGis::WKBLineString: // Line center
543+ {
544+ assert ( geom+sizeof (int )<=geomend );
545+ int nPoints = *(unsigned int *)geom;
546+ geom += sizeof (int );
547+
548+ assert ( geom+nPoints*sizeof (double )*dims<=geomend );
549+
550+ // get line center
551+ double *pts = (double *)geom;
552+ double tl = 0.0 ;
553+ for (int i = 1 ; i < nPoints; i++)
522554 {
523- x = (double *) (geom + 5 );
524- y = (double *) (geom + 5 + sizeof (double ));
525- point.set (*x, *y);
526- nextFeature += 1 + sizeOfInt + sizeOfDouble*2 ;
555+ double dx = pts[dims*i] - pts[dims*(i-1 )];
556+ double dy = pts[dims*i+1 ] - pts[dims*(i-1 )+1 ];
557+ tl += sqrt (dx*dx + dy*dy);
527558 }
528- break ;
529- case QGis::WKBLineString25D:
530- hasZValue = true ;
531- case QGis::WKBLineString: // Line center
559+ tl /= 2.0 ;
560+
561+ // find line center
562+ double l = 0.0 ;
563+ for (int i=1 ; i < nPoints; i++)
532564 {
533- double dx, dy, tl, l;
534- ptr = geom + 5 ;
535- nPoints = (int *)ptr;
536- if (hasZValue)
537- {
538- nextFeature += 1 + sizeOfInt*2 + (*nPoints)*sizeOfDouble*3 ;
539- }
540- else
541- {
542- nextFeature += 1 + sizeOfInt*2 + (*nPoints)*sizeOfDouble*2 ;
543- }
544- ptr = geom + 1 + 2 * sizeof (int );
565+ double dx = pts[dims*i] - pts[dims*(i-1 )];
566+ double dy = pts[dims*i+1 ] - pts[dims*(i-1 )+1 ];
567+ double dl = sqrt (dx*dx + dy*dy);
545568
546- tl = 0 ;
547- for (int i = 1 ; i < *nPoints; i++)
569+ if ( l+dl > tl )
548570 {
549- if (hasZValue)
550- {
551- dx = ((double *)ptr)[3 *i] - ((double *)ptr)[3 *i-3 ];
552- dy = ((double *)ptr)[3 *i+1 ] - ((double *)ptr)[3 *i-2 ];
553- }
554- else
555- {
556- dx = ((double *)ptr)[2 *i] - ((double *)ptr)[2 *i-2 ];
557- dy = ((double *)ptr)[2 *i+1 ] - ((double *)ptr)[2 *i-1 ];
558- }
559- tl += sqrt (dx*dx + dy*dy);
560- }
561- tl /= 2 ;
571+ double k = (tl-l)/dl;
562572
563- l = 0 ;
564- for (int i = 1 ; i < *nPoints; i++)
565- {
566- double dl;
567- if (hasZValue)
568- {
569- dx = ((double *)ptr)[3 *i] - ((double *)ptr)[3 *i-3 ];
570- dy = ((double *)ptr)[3 *i+1 ] - ((double *)ptr)[3 *i-2 ];
571- }
572- else
573- {
574- dx = ((double *)ptr)[2 *i] - ((double *)ptr)[2 *i-2 ];
575- dy = ((double *)ptr)[2 *i+1 ] - ((double *)ptr)[2 *i-1 ];
576- }
577- dl = sqrt (dx*dx + dy*dy);
578-
579- if ( l+dl > tl )
580- {
581- l = tl - l;
582- double k = l/dl;
583-
584- if (hasZValue)
585- {
586- point.setX ( ((double *)ptr)[3 *i-3 ] + k * dx );
587- point.setY ( ((double *)ptr)[3 *i-2 ] + k * dy );
588- }
589- else
590- {
591- point.setX ( ((double *)ptr)[2 *i-2 ] + k * dx );
592- point.setY ( ((double *)ptr)[2 *i-1 ] + k * dy );
593- }
594- break ;
595- }
596- l += dl;
573+ point.set ( pts[dims*(i-1 )] + k * dx,
574+ pts[dims*(i-1 )+1 ] + k * dy);
575+ break ;
597576 }
577+
578+ l += dl;
598579 }
599- break ;
600580
601- case QGis::WKBPolygon25D:
602- hasZValue = true ;
603- case QGis::WKBPolygon:
581+ geom += nPoints*sizeof (double )*dims;
582+ }
583+ break ;
584+
585+ case QGis::WKBPolygon25D:
586+ dims = 3 ;
587+ case QGis::WKBPolygon: // centroid of outer ring
588+ {
589+ assert ( geom+sizeof (int )<=geomend);
590+ int nRings = *(unsigned int *)geom;
591+ geom += sizeof (int );
592+
593+ for (int i=0 ; i<nRings; ++i)
604594 {
605- double sx, sy;
606- ptr = geom + 1 + 2 * sizeof (int ); // set pointer to the first ring
607- nPoints = (int *) ptr;
608- ptr += 4 ;
609- sx = sy = 0 ;
610- for (int i = 0 ; i < *nPoints-1 ; i++)
611- {
612- if (hasZValue)
613- {
614- sx += ((double *)ptr)[3 *i];
615- sy += ((double *)ptr)[3 *i+1 ];
616- }
617- else
618- {
619- sx += ((double *)ptr)[2 *i];
620- sy += ((double *)ptr)[2 *i+1 ];
621- }
622- }
623- point.setX ( sx/(*nPoints-1 ) );
624- point.setY ( sy/(*nPoints-1 ) );
625- // Work out a pointer to the next feature after this one.
626- int numRings = (int )(*(geom+1 +sizeOfInt));
627- unsigned char * nextRing = nextFeature + 1 + 2 *sizeOfInt;
628- for (int i = 0 ; i < numRings; ++i)
629- {
630- int numPoints = (int )(*nextRing);
631- // get the start of the next ring
632- if (hasZValue)
633- {
634- nextRing += sizeOfInt + numPoints*sizeOfDouble*3 ;
635- }
636- else
637- {
638- nextRing += sizeOfInt + numPoints*sizeOfDouble*2 ;
639- }
595+ assert ( geom+sizeof (int )<=geomend );
596+ int nPoints = *(unsigned int *)geom;
597+ geom += sizeof (int );
598+
599+ assert ( geom+nPoints*sizeof (double )*dims<=geomend );
600+
601+ if ( i==0 ) {
602+ double sx=0.0 , sy=0.0 ;
603+ double *pts = (double *) geom;
604+ for (int j=0 ; j<nPoints-1 ; j++) {
605+ sx += pts[dims*j];
606+ sy += pts[dims*j+1 ];
607+ }
608+ point.set ( sx/(nPoints-1 ),
609+ sy/(nPoints-1 ) );
640610 }
641- nextFeature = nextRing;
642- }
643- break ;
644611
645- default :
646- // To get here is a bug because our caller should be filtering
647- // on wkb type.
648- break ;
612+ geom += nPoints*sizeof (double )*dims;
613+ }
649614 }
650- return nextFeature;
615+ break ;
616+
617+ default :
618+ // To get here is a bug because our caller should be filtering
619+ // on wkb type.
620+ QgsDebugMsg (" unsupported wkb type" );
621+ return NULL ;
622+ }
623+
624+ return geom;
651625}
652626
653627static int _elementFieldIndex (QDomElement& el)
0 commit comments