Bug 294137 - mozilla accepts illegal syntax on transform attribute.

Patch by wellsk@us.ibm.com, tor.  r+sr=roc


git-svn-id: svn://10.0.0.236/trunk@211686 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
tor%cs.brown.edu
2006-09-14 13:48:36 +00:00
parent 2b1e9b3f30
commit 7da2b696d4
4 changed files with 502 additions and 159 deletions

View File

@@ -134,6 +134,7 @@ CPPSRCS = \
nsSVGTitleElement.cpp \
nsSVGTransform.cpp \
nsSVGTransformList.cpp \
nsSVGTransformListParser.cpp \
nsSVGUseElement.cpp \
nsSVGValue.cpp \
$(NULL)

View File

@@ -38,6 +38,7 @@
* ***** END LICENSE BLOCK ***** */
#include "nsSVGTransformList.h"
#include "nsSVGTransformListParser.h"
#include "nsSVGTransform.h"
#include "nsSVGMatrix.h"
#include "nsDOMError.h"
@@ -130,119 +131,17 @@ NS_IMETHODIMP
nsSVGTransformList::SetValueString(const nsAString& aValue)
{
// XXX: we don't implement the _exact_ BNF given in the
// specs.
// specs.
nsresult rv = NS_OK;
char *str = ToNewCString(aValue);
char* rest = str;
char* keyword;
char* args;
const char* delimiters1 = "\x20\x9\xD\xA,(";
const char* delimiters2 = "()";
// parse transform attribute value
nsCOMArray<nsIDOMSVGTransform> xforms;
while ((keyword = nsCRT::strtok(rest, delimiters1, &rest))) {
nsSVGTransformListParser parser(&xforms);
rv = parser.Parse(aValue);
while (rest && isspace(*rest))
++rest;
if (!(args = nsCRT::strtok(rest, delimiters2, &rest))) {
rv = NS_ERROR_FAILURE;
break; // parse error
}
nsCOMPtr<nsIDOMSVGTransform> transform;
NS_NewSVGTransform(getter_AddRefs(transform));
if (!transform) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
nsCOMPtr<nsIAtom> keyatom = do_GetAtom(keyword);
if (keyatom == nsSVGAtoms::translate) {
// tx [ty=0]
float t[2] = { 0.f };
PRInt32 num_parsed = ParseParameterList(args, t, 2);
if (num_parsed != 1 && num_parsed != 2) {
rv = NS_ERROR_FAILURE;
break; // parse error
}
transform->SetTranslate(t[0], t[1]);
}
else if (keyatom == nsSVGAtoms::scale) {
// sx [sy=sx]
float s[2] = { 0.f };
PRInt32 num_parsed = ParseParameterList(args, s, 2);
if (num_parsed != 1 && num_parsed != 2) {
rv = NS_ERROR_FAILURE;
break; // parse error
}
if (num_parsed == 1)
s[1] = s[0];
transform->SetScale(s[0], s[1]);
}
else if (keyatom == nsSVGAtoms::rotate) {
// r [x0=0 y0=0]
float r[3] = { 0.f };
PRInt32 num_parsed = ParseParameterList(args, r, 3);
if (num_parsed != 1 && num_parsed != 3) {
rv = NS_ERROR_FAILURE;
break; // parse error
}
transform->SetRotate(r[0], r[1], r[2]);
}
else if (keyatom == nsSVGAtoms::skewX) {
// x-angle
float angle;
PRInt32 num_parsed = ParseParameterList(args, &angle, 1);
if (num_parsed != 1) {
rv = NS_ERROR_FAILURE;
break; // parse error
}
transform->SetSkewX(angle);
}
else if (keyatom == nsSVGAtoms::skewY) {
// y-angle
float angle;
PRInt32 num_parsed = ParseParameterList(args, &angle, 1);
if (num_parsed != 1) {
rv = NS_ERROR_FAILURE;
break; // parse error
}
transform->SetSkewY(angle);
}
else if (keyatom == nsSVGAtoms::matrix) {
// a b c d e f
float m[6];
PRInt32 num_parsed = ParseParameterList(args, m, 6);
if (num_parsed != 6) {
rv = NS_ERROR_FAILURE;
break; // parse error
}
nsCOMPtr<nsIDOMSVGMatrix> matrix;
NS_NewSVGMatrix(getter_AddRefs(matrix),
m[0], m[1], m[2], m[3], m[4], m[5]);
NS_ASSERTION(matrix, "couldn't create matrix");
transform->SetMatrix(matrix);
}
else { // parse error
rv = NS_ERROR_FAILURE;
break;
}
xforms.AppendObject(transform);
}
if (keyword || NS_FAILED(rv)) {
// there was a parse error.
if (NS_FAILED(rv)) {
// there was a parse error.
rv = NS_ERROR_FAILURE;
}
else {
@@ -255,59 +154,9 @@ nsSVGTransformList::SetValueString(const nsAString& aValue)
DidModify();
}
nsMemory::Free(str);
return rv;
}
// helper for SetValueString
// parse up to nvars comma-separated parameters into vars, returning
// the number of variables actually provided.
//
// -1 will be returned if any of the arguments can't be converted to a
// float. The return value may be higher than nvars, if more
// arguments were provided; no attempt is made to actually parse any
// more arguments than nvars.
//
// note that this would accept ",,," and will just return 0
// arguments found, instead of -1. This is because the numeric
// values can have spaces surrounding them, but the spaces can also
// be used as delimiters. strtok doesn't tell us what the
// delimiter is, so we have no way to distinguish
// ' 20,20 ' from ',,20,20,,' (or from ',,20 20,,', for that matter).
//
// XXX If someone knows for sure that it's not ok to mix commas and
// spaces as delimiters, then we can scan the string for a comma,
// and if found use a delimiter of just ",", otherwise use a set of
// spaces (without a comma).
PRInt32
nsSVGTransformList::ParseParameterList(char *paramstr, float *vars, PRInt32 nvars)
{
if (!paramstr)
return 0;
char *arg, *argend, *argrest = paramstr;
int num_args_found = 0;
float f;
const char* arg_delimiters = "\x20\x09\x0d\x0a,";
while ((arg = nsCRT::strtok(argrest, arg_delimiters, &argrest))) {
if (num_args_found < nvars) {
f = (float) PR_strtod(arg, &argend);
if (arg == argend || *argend != '\0')
return -1;
vars[num_args_found] = f;
}
arg = argrest;
num_args_found++;
}
return num_args_found;
}
NS_IMETHODIMP
nsSVGTransformList::GetValueString(nsAString& aValue)
{

View File

@@ -0,0 +1,405 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is
* IBM Corporation
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsSVGTransformListParser.h"
#include "prdtoa.h"
#include "nsSVGTransform.h"
#include "nsSVGMatrix.h"
#include "nsDOMError.h"
#include "nsSVGAtoms.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
#include "nsCOMArray.h"
#include "nsContentUtils.h"
#include "nsIDOMClassInfo.h"
//----------------------------------------------------------------------
// public interface
nsSVGTransformListParser::nsSVGTransformListParser(nsCOMArray<nsIDOMSVGTransform>* aTransforms)
: mTransform(aTransforms)
{
}
//----------------------------------------------------------------------
// private methods
nsresult
nsSVGTransformListParser::Match()
{
return MatchTransformList();
}
nsresult
nsSVGTransformListParser::MatchTransformList()
{
MatchWsp();
if (IsTokenTransformStarter()) {
ENSURE_MATCHED(MatchTransforms());
}
MatchWsp();
return NS_OK;
}
nsresult
nsSVGTransformListParser::MatchTransforms()
{
ENSURE_MATCHED(MatchTransform());
while (mTokenType != END) {
const char* pos = mTokenPos;
/* Curiously the SVG BNF allows multiple comma-wsp between transforms */
while (IsTokenCommaWspStarter()) {
ENSURE_MATCHED(MatchCommaWsp());
}
if (IsTokenTransformStarter()) {
ENSURE_MATCHED(MatchTransform());
}
else {
if (pos != mTokenPos) RewindTo(pos);
break;
}
}
return NS_OK;
}
nsresult
nsSVGTransformListParser::GetTransformToken(nsIAtom** aKeyAtom,
PRBool aAdvancePos)
{
if (mTokenType != OTHER || *mTokenPos == '\0') {
return NS_ERROR_FAILURE;
}
nsresult rv = NS_OK;
const char* delimiters = "\x20\x9\xD\xA,(";
char* delimiterStart = PL_strnpbrk(mTokenPos, delimiters, 11);
if (delimiterStart != 0) {
/* save this character and null it out */
char holdingChar = *delimiterStart;
*delimiterStart = '\0';
if (mTokenPos != 0 && nsCRT::strlen(mTokenPos) > 0) {
*aKeyAtom = NS_NewAtom(mTokenPos);
if (aAdvancePos) {
mInputPos = mTokenPos + nsCRT::strlen(mTokenPos);
mTokenPos = mInputPos;
}
}
else {
rv = NS_ERROR_FAILURE;
}
/* reset character back to original */
*delimiterStart = holdingChar;
}
else {
rv = NS_ERROR_FAILURE;
}
return rv;
}
nsresult
nsSVGTransformListParser::MatchTransform()
{
nsCOMPtr<nsIAtom> keyatom;
nsresult rv = GetTransformToken(getter_AddRefs(keyatom), PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
if (keyatom == nsSVGAtoms::translate) {
ENSURE_MATCHED(MatchTranslate());
}
else if (keyatom == nsSVGAtoms::scale) {
ENSURE_MATCHED(MatchScale());
}
else if (keyatom == nsSVGAtoms::rotate) {
ENSURE_MATCHED(MatchRotate());
}
else if (keyatom == nsSVGAtoms::skewX) {
ENSURE_MATCHED(MatchSkewX());
}
else if (keyatom == nsSVGAtoms::skewY) {
ENSURE_MATCHED(MatchSkewY());
}
else if (keyatom == nsSVGAtoms::matrix) {
ENSURE_MATCHED(MatchMatrix());
}
else {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
PRBool
nsSVGTransformListParser::IsTokenTransformStarter()
{
nsCOMPtr<nsIAtom> keyatom;
nsresult rv = GetTransformToken(getter_AddRefs(keyatom), PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
if (keyatom == nsSVGAtoms::translate ||
keyatom == nsSVGAtoms::scale ||
keyatom == nsSVGAtoms::rotate ||
keyatom == nsSVGAtoms::skewX ||
keyatom == nsSVGAtoms::skewY ||
keyatom == nsSVGAtoms::matrix) {
return PR_TRUE;
}
return PR_FALSE;
}
nsresult
nsSVGTransformListParser::MatchNumberArguments(float *aResult,
PRUint32 aMaxNum,
PRUint32 *aParsedNum)
{
*aParsedNum = 0;
MatchWsp();
ENSURE_MATCHED(MatchLeftParen());
MatchWsp();
ENSURE_MATCHED(MatchNumber(&aResult[0]));
*aParsedNum = 1;
while (IsTokenCommaWspStarter()) {
MatchWsp();
if (mTokenType == RIGHT_PAREN) {
break;
}
if (*aParsedNum == aMaxNum) {
return NS_ERROR_FAILURE;
}
if (IsTokenCommaWspStarter()) {
MatchCommaWsp();
}
ENSURE_MATCHED(MatchNumber(&aResult[(*aParsedNum)++]));
}
MatchWsp();
ENSURE_MATCHED(MatchRightParen());
return NS_OK;
}
nsIDOMSVGTransform *
nsSVGTransformListParser::AppendTransform()
{
nsCOMPtr<nsIDOMSVGTransform> transform;
NS_NewSVGTransform(getter_AddRefs(transform));
if (transform) {
mTransform->AppendObject(transform);
}
return transform;
}
nsresult
nsSVGTransformListParser::MatchTranslate()
{
GetNextToken();
float t[2];
PRUint32 count;
ENSURE_MATCHED(MatchNumberArguments(t, NS_ARRAY_LENGTH(t), &count));
switch (count) {
case 1:
t[1] = 0.f;
// fall-through
case 2:
{
nsIDOMSVGTransform *transform = AppendTransform();
NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
transform->SetTranslate(t[0], t[1]);
break;
}
default:
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsSVGTransformListParser::MatchScale()
{
GetNextToken();
float s[2];
PRUint32 count;
ENSURE_MATCHED(MatchNumberArguments(s, NS_ARRAY_LENGTH(s), &count));
switch (count) {
case 1:
s[1] = s[0];
// fall-through
case 2:
{
nsIDOMSVGTransform *transform = AppendTransform();
NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
transform->SetScale(s[0], s[1]);
break;
}
default:
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsSVGTransformListParser::MatchRotate()
{
GetNextToken();
float r[3];
PRUint32 count;
ENSURE_MATCHED(MatchNumberArguments(r, NS_ARRAY_LENGTH(r), &count));
switch (count) {
case 1:
r[1] = r[2] = 0.f;
// fall-through
case 3:
{
nsIDOMSVGTransform *transform = AppendTransform();
NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
transform->SetRotate(r[0], r[1], r[2]);
break;
}
default:
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsSVGTransformListParser::MatchSkewX()
{
GetNextToken();
float skew;
PRUint32 count;
ENSURE_MATCHED(MatchNumberArguments(&skew, 1, &count));
if (count != 1) {
return NS_ERROR_FAILURE;
}
nsIDOMSVGTransform *transform = AppendTransform();
NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
transform->SetSkewX(skew);
return NS_OK;
}
nsresult
nsSVGTransformListParser::MatchSkewY()
{
GetNextToken();
float skew;
PRUint32 count;
ENSURE_MATCHED(MatchNumberArguments(&skew, 1, &count));
if (count != 1) {
return NS_ERROR_FAILURE;
}
nsIDOMSVGTransform *transform = AppendTransform();
NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
transform->SetSkewY(skew);
return NS_OK;
}
nsresult
nsSVGTransformListParser::MatchMatrix()
{
GetNextToken();
float m[6];
PRUint32 count;
ENSURE_MATCHED(MatchNumberArguments(m, NS_ARRAY_LENGTH(m), &count));
if (count != 6) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMSVGMatrix> matrix;
NS_NewSVGMatrix(getter_AddRefs(matrix),
m[0], m[1], m[2], m[3], m[4], m[5]);
NS_ENSURE_TRUE(matrix, NS_ERROR_OUT_OF_MEMORY);
nsIDOMSVGTransform *transform = AppendTransform();
NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
transform->SetMatrix(matrix);
return NS_OK;
}

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Mozilla SVG project.
*
* The Initial Developer of the Original Code is
* IBM Corporation
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NS_SVGTRANSFORMLISTPARSER_H__
#define __NS_SVGTRANSFORMLISTPARSER_H__
#include "nsSVGDataParser.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsIDOMSVGTransformList.h"
#include "nsIAtom.h"
////////////////////////////////////////////////////////////////////////
// nsSVGTransformListParser: taken from nsSVGPathDataParser, a simple
// recursive descent parser that builds the transform lists from the
// transform attributes. The grammar for path data
// can be found in SVG 1.1, chapter 7.
// http://www.w3.org/TR/SVG11/coords.html#TransformAttribute
class nsSVGTransformListParser : public nsSVGDataParser
{
public:
nsSVGTransformListParser(nsCOMArray<nsIDOMSVGTransform>* aTransforms);
private:
nsCOMArray<nsIDOMSVGTransform> *mTransform;
// helpers
nsresult Match();
nsresult MatchNumberArguments(float *aResult,
PRUint32 aMaxNum,
PRUint32 *aParsedNum);
nsIDOMSVGTransform *AppendTransform();
nsresult MatchTransformList();
nsresult GetTransformToken(nsIAtom** aKeyatom, PRBool aAdvancePos);
nsresult MatchTransforms();
nsresult MatchTransform();
PRBool IsTokenTransformStarter();
nsresult MatchTranslate();
nsresult MatchScale();
nsresult MatchRotate();
nsresult MatchSkewX();
nsresult MatchSkewY();
nsresult MatchMatrix();
};
#endif // __NS_SVGTRANSFORMLISTPARSER_H__