Program: 91924
Project: 91924
Buggy source:
/** 
 * Parses a   {@code "CS"} element followed by all {@code "AXIS"} elements.This element has the following pattern (simplified): {@preformat textCS["<type>", dimension], AXIS["<name>", NORTH | SOUTH | EAST | WEST | UP | DOWN | OTHER], UNIT["<name>", <conversion factor>], etc.}This element is different from all other elements parsed by   {@code GeodeticObjectParser}in that its components are sibling elements rather than child elements of the CS element. <p>The optional   {@code "UNIT[…]"} element shall be parsed by the caller. That element may appear after the{@code "CS[…]"} element (not inside). The unit may be forced to some dimension (e.g. {@code "LengthUnit"}) or be any kind of unit, depending on the context in which this   {@code parseCoordinateSystem(…)} method isinvoked.</p> <div class="section">Variants of Cartesian type</div> The  {@link WKTKeywords#Cartesian} type may be used for projected, geocentric or other kinds of CRS.However while all those variants are of the same CS type, their axis names and directions differ. Current implementation uses the following rules: <ul> <li>If the datum is not geodetic, then the axes of the Cartesian CS are unknown.</li> <li>Otherwise if  {@code dimension is 2}, then the CS is assumed to be for a projected CRS.</li> <li>Otherwise if   {@code dimension is 3}, then the CS is assumed to be for a geocentric CRS.</li> </ul>
 * @param parent      The parent element.
 * @param type        The expected type (Cartesian | ellipsoidal | vertical | etc…), or null if unknown.
 * @param dimension   The minimal number of dimensions. Can be 1 if unknown.
 * @param isWKT1      {@code true} if the parent element is an element from the WKT 1 standard.
 * @param defaultUnit The contextual unit (usually {@code SI.METRE} or {@code SI.RADIAN}), or   {@code null} if unknown.
 * @param datum       The datum of the enclosing CRS, or {@code null} if unknown.
 * @return The {@code "CS"},   {@code "UNIT"} and/or {@code "AXIS"} elements as a Coordinate System, or {@code null}.
 * @throws ParseException if an element can not be parsed.
 * @throws FactoryException if the factory can not create the coordinate system.
 */
private CoordinateSystem parseCoordinateSystem(final Element parent,String type,int dimension,final boolean isWKT1,final Unit<?> defaultUnit,final Datum datum) throws ParseException, FactoryException {
  axisOrder.clear();
  final boolean is3D=(dimension >= 3);
  Map<String,Object> csProperties=null;
  if (!isWKT1) {
    final Element element=parent.pullElement(OPTIONAL,WKTKeywords.CS);
    if (element != null) {
      final String expected=type;
      type=element.pullVoidElement("String_Node_Str").keyword;
      dimension=element.pullInteger("String_Node_Str");
      csProperties=new HashMap<>(parseMetadataAndClose(element,"String_Node_Str",null));
      if (expected != null) {
        if (!expected.equalsIgnoreCase(type)) {
          throw new LocalizedParseException(errorLocale,Errors.Keys.UnexpectedValueInElement_2,new String[]{WKTKeywords.CS,type},element.offset);
        }
      }
      if (dimension <= 0 || dimension > 1000) {
        final short key;
        final Object[] args;
        if (dimension <= 0) {
          key=Errors.Keys.ValueNotGreaterThanZero_2;
          args=new Object[]{"String_Node_Str",dimension};
        }
 else {
          key=Errors.Keys.ExcessiveNumberOfDimensions_1;
          args=new Object[]{dimension};
        }
        throw new LocalizedParseException(errorLocale,key,args,element.offset);
      }
      type=type.equalsIgnoreCase(WKTKeywords.Cartesian) ? WKTKeywords.Cartesian : type.toLowerCase(symbols.getLocale());
    }
  }
  CoordinateSystemAxis[] axes=null;
  CoordinateSystemAxis axis=parseAxis(type == null ? MANDATORY : OPTIONAL,parent,type,defaultUnit);
  if (axis != null) {
    final List<CoordinateSystemAxis> list=new ArrayList<>(dimension + 2);
    do {
      list.add(axis);
      axis=parseAxis(list.size() < dimension ? MANDATORY : OPTIONAL,parent,type,defaultUnit);
    }
 while (axis != null);
    if (!isWKT1 || !ignoreAxes) {
      axes=list.toArray(new CoordinateSystemAxis[list.size()]);
      Arrays.sort(axes,this);
    }
  }
  if (axes == null) {
    if (type == null) {
      throw parent.missingComponent(WKTKeywords.Axis);
    }
    String nx=null, x=null;
    String ny=null, y=null;
    String nz=null, z=null;
    AxisDirection dx=AxisDirection.EAST;
    AxisDirection dy=AxisDirection.NORTH;
    AxisDirection direction=null;
    Unit<?> unit=defaultUnit;
switch (type) {
case WKTKeywords.Cartesian:
{
        if (!(datum instanceof GeodeticDatum)) {
          throw parent.missingComponent(WKTKeywords.Axis);
        }
        if (defaultUnit == null) {
          throw parent.missingComponent(WKTKeywords.LengthUnit);
        }
        if (is3D) {
          return referencing.getGeocentricCS(defaultUnit.asType(Length.class));
        }
        nx=AxisNames.EASTING;
        x="String_Node_Str";
        ny=AxisNames.NORTHING;
        y="String_Node_Str";
        if (dimension >= 3) {
          z="String_Node_Str";
          nz=AxisNames.ELLIPSOIDAL_HEIGHT;
          unit=SI.METRE;
        }
        break;
      }
case WKTKeywords.ellipsoidal:
{
      if (defaultUnit == null) {
        throw parent.missingComponent(WKTKeywords.AngleUnit);
      }
      if (isWKT1) {
        nx=AxisNames.GEODETIC_LONGITUDE;
        x="String_Node_Str";
        ny=AxisNames.GEODETIC_LATITUDE;
        y="String_Node_Str";
      }
 else {
        nx=AxisNames.GEODETIC_LATITUDE;
        x="String_Node_Str";
        dx=AxisDirection.NORTH;
        ny=AxisNames.GEODETIC_LONGITUDE;
        y="String_Node_Str";
        dy=AxisDirection.EAST;
      }
      if (dimension >= 3) {
        direction=AxisDirection.UP;
        z="String_Node_Str";
        nz=AxisNames.ELLIPSOIDAL_HEIGHT;
        unit=SI.METRE;
      }
      break;
    }
case WKTKeywords.vertical:
{
    if (defaultUnit == null) {
      throw parent.missingComponent(WKTKeywords.Unit);
    }
    z="String_Node_Str";
    nz="String_Node_Str";
    direction=AxisDirection.UP;
    if (datum instanceof VerticalDatum) {
      final VerticalDatumType vt=((VerticalDatum)datum).getVerticalDatumType();
      if (VerticalDatumType.GEOIDAL.equals(vt)) {
        nz=AxisNames.GRAVITY_RELATED_HEIGHT;
        z="String_Node_Str";
      }
 else       if (VerticalDatumType.DEPTH.equals(vt)) {
        direction=AxisDirection.DOWN;
        nz=AxisNames.DEPTH;
        z="String_Node_Str";
      }
 else       if (VerticalDatumTypes.ELLIPSOIDAL.equals(vt)) {
        nz=AxisNames.ELLIPSOIDAL_HEIGHT;
      }
    }
    break;
  }
case WKTKeywords.temporal:
{
  if (defaultUnit == null) {
    throw parent.missingComponent(WKTKeywords.TimeUnit);
  }
  direction=AxisDirection.FUTURE;
  nz="String_Node_Str";
  z="String_Node_Str";
  break;
}
default :
{
throw parent.missingComponent(WKTKeywords.Axis);
}
}
int i=0;
axes=new CoordinateSystemAxis[dimension];
if (x != null && i < dimension) axes[i++]=csFactory.createCoordinateSystemAxis(singletonMap(CoordinateSystemAxis.NAME_KEY,nx),x,dx,defaultUnit);
if (y != null && i < dimension) axes[i++]=csFactory.createCoordinateSystemAxis(singletonMap(CoordinateSystemAxis.NAME_KEY,ny),y,dy,defaultUnit);
if (z != null && i < dimension) axes[i++]=csFactory.createCoordinateSystemAxis(singletonMap(CoordinateSystemAxis.NAME_KEY,nz),z,direction,unit);
}
final String name;
{
final StringBuilder buffer=new StringBuilder();
if (type != null && !type.isEmpty()) {
final int c=type.codePointAt(0);
buffer.appendCodePoint(Character.toUpperCase(c)).append(type,Character.charCount(c),type.length()).append(' ');
}
name=AxisDirections.appendTo(buffer.append("String_Node_Str"),axes);
}
if (csProperties == null) {
csProperties=singletonMap(CoordinateSystem.NAME_KEY,name);
}
 else {
csProperties.put(CoordinateSystem.NAME_KEY,name);
}
if (type == null) {
return referencing.createAbstractCS(csProperties,axes);
}
switch (type) {
case WKTKeywords.ellipsoidal:
{
switch (axes.length) {
case 2:
return csFactory.createEllipsoidalCS(csProperties,axes[0],axes[1]);
case 3:
return csFactory.createEllipsoidalCS(csProperties,axes[0],axes[1],axes[2]);
}
dimension=(axes.length < 2) ? 2 : 3;
break;
}
case WKTKeywords.Cartesian:
{
switch (axes.length) {
case 2:
return csFactory.createCartesianCS(csProperties,axes[0],axes[1]);
case 3:
return csFactory.createCartesianCS(csProperties,axes[0],axes[1],axes[2]);
}
dimension=(axes.length < 2) ? 2 : 3;
break;
}
case WKTKeywords.affine:
{
switch (axes.length) {
case 2:
return csFactory.createAffineCS(csProperties,axes[0],axes[1]);
case 3:
return csFactory.createAffineCS(csProperties,axes[0],axes[1],axes[2]);
}
dimension=(axes.length < 2) ? 2 : 3;
break;
}
case WKTKeywords.vertical:
{
if (axes.length != (dimension=1)) break;
return csFactory.createVerticalCS(csProperties,axes[0]);
}
case WKTKeywords.temporal:
{
if (axes.length != (dimension=1)) break;
return csFactory.createTimeCS(csProperties,axes[0]);
}
case WKTKeywords.linear:
{
if (axes.length != (dimension=1)) break;
return csFactory.createLinearCS(csProperties,axes[0]);
}
case WKTKeywords.polar:
{
if (axes.length != (dimension=2)) break;
return csFactory.createPolarCS(csProperties,axes[0],axes[1]);
}
case WKTKeywords.cylindrical:
{
if (axes.length != (dimension=3)) break;
return csFactory.createCylindricalCS(csProperties,axes[0],axes[1],axes[2]);
}
case WKTKeywords.spherical:
{
if (axes.length != (dimension=3)) break;
return csFactory.createSphericalCS(csProperties,axes[0],axes[1],axes[2]);
}
case WKTKeywords.parametric:
{
return referencing.createAbstractCS(csProperties,axes);
}
default :
{
warning(Errors.formatInternational(Errors.Keys.UnknownType_1,type),null);
return referencing.createAbstractCS(csProperties,axes);
}
}
throw new LocalizedParseException(errorLocale,(axes.length > dimension) ? Errors.Keys.TooManyOccurrences_2 : Errors.Keys.TooFewOccurrences_2,new Object[]{dimension,WKTKeywords.Axis},parent.offset);
}

Fixed version (ground truth):
/** 
 * Parses a   {@code "CS"} element followed by all {@code "AXIS"} elements.This element has the following pattern (simplified): {@preformat wktCS["<type>", dimension], AXIS["<name>", NORTH | SOUTH | EAST | WEST | UP | DOWN | OTHER], UNIT["<name>", <conversion factor>], etc.}This element is different from all other elements parsed by   {@code GeodeticObjectParser}in that its components are sibling elements rather than child elements of the CS element. <p>The optional   {@code "UNIT[…]"} element shall be parsed by the caller. That element may appear after the{@code "CS[…]"} element (not inside). The unit may be forced to some dimension (e.g. {@code "LengthUnit"}) or be any kind of unit, depending on the context in which this   {@code parseCoordinateSystem(…)} method isinvoked.</p> <div class="section">Variants of Cartesian type</div> The  {@link WKTKeywords#Cartesian} type may be used for projected, geocentric or other kinds of CRS.However while all those variants are of the same CS type, their axis names and directions differ. Current implementation uses the following rules: <ul> <li>If the datum is not geodetic, then the axes of the Cartesian CS are unknown.</li> <li>Otherwise if  {@code dimension is 2}, then the CS is assumed to be for a projected CRS.</li> <li>Otherwise if   {@code dimension is 3}, then the CS is assumed to be for a geocentric CRS.</li> </ul>
 * @param parent      The parent element.
 * @param type        The expected type (Cartesian | ellipsoidal | vertical | etc…), or null if unknown.
 * @param dimension   The minimal number of dimensions. Can be 1 if unknown.
 * @param isWKT1      {@code true} if the parent element is an element from the WKT 1 standard.
 * @param defaultUnit The contextual unit (usually {@code SI.METRE} or {@code SI.RADIAN}), or   {@code null} if unknown.
 * @param datum       The datum of the enclosing CRS, or {@code null} if unknown.
 * @return The {@code "CS"},   {@code "UNIT"} and/or {@code "AXIS"} elements as a Coordinate System, or {@code null}.
 * @throws ParseException if an element can not be parsed.
 * @throws FactoryException if the factory can not create the coordinate system.
 */
private CoordinateSystem parseCoordinateSystem(final Element parent,String type,int dimension,final boolean isWKT1,final Unit<?> defaultUnit,final Datum datum) throws ParseException, FactoryException {
  axisOrder.clear();
  final boolean is3D=(dimension >= 3);
  Map<String,Object> csProperties=null;
  if (!isWKT1) {
    final Element element=parent.pullElement(OPTIONAL,WKTKeywords.CS);
    if (element != null) {
      final String expected=type;
      type=element.pullVoidElement("String_Node_Str").keyword;
      dimension=element.pullInteger("String_Node_Str");
      csProperties=new HashMap<>(parseMetadataAndClose(element,"String_Node_Str",null));
      if (expected != null) {
        if (!expected.equalsIgnoreCase(type)) {
          throw new LocalizedParseException(errorLocale,Errors.Keys.UnexpectedValueInElement_2,new String[]{WKTKeywords.CS,type},element.offset);
        }
      }
      if (dimension <= 0 || dimension > 1000) {
        final short key;
        final Object[] args;
        if (dimension <= 0) {
          key=Errors.Keys.ValueNotGreaterThanZero_2;
          args=new Object[]{"String_Node_Str",dimension};
        }
 else {
          key=Errors.Keys.ExcessiveNumberOfDimensions_1;
          args=new Object[]{dimension};
        }
        throw new LocalizedParseException(errorLocale,key,args,element.offset);
      }
      type=type.equalsIgnoreCase(WKTKeywords.Cartesian) ? WKTKeywords.Cartesian : type.toLowerCase(symbols.getLocale());
    }
  }
  CoordinateSystemAxis[] axes=null;
  CoordinateSystemAxis axis=parseAxis(type == null ? MANDATORY : OPTIONAL,parent,type,defaultUnit);
  if (axis != null) {
    final List<CoordinateSystemAxis> list=new ArrayList<>(dimension + 2);
    do {
      list.add(axis);
      axis=parseAxis(list.size() < dimension ? MANDATORY : OPTIONAL,parent,type,defaultUnit);
    }
 while (axis != null);
    if (!isWKT1 || !ignoreAxes) {
      axes=list.toArray(new CoordinateSystemAxis[list.size()]);
      Arrays.sort(axes,this);
    }
  }
  if (axes == null) {
    if (type == null) {
      throw parent.missingComponent(WKTKeywords.Axis);
    }
    String nx=null, x=null;
    String ny=null, y=null;
    String nz=null, z=null;
    AxisDirection dx=AxisDirection.EAST;
    AxisDirection dy=AxisDirection.NORTH;
    AxisDirection direction=null;
    Unit<?> unit=defaultUnit;
switch (type) {
case WKTKeywords.Cartesian:
{
        if (!(datum instanceof GeodeticDatum)) {
          throw parent.missingComponent(WKTKeywords.Axis);
        }
        if (defaultUnit == null) {
          throw parent.missingComponent(WKTKeywords.LengthUnit);
        }
        if (is3D) {
          return referencing.getGeocentricCS(defaultUnit.asType(Length.class));
        }
        nx=AxisNames.EASTING;
        x="String_Node_Str";
        ny=AxisNames.NORTHING;
        y="String_Node_Str";
        if (dimension >= 3) {
          z="String_Node_Str";
          nz=AxisNames.ELLIPSOIDAL_HEIGHT;
          unit=SI.METRE;
        }
        break;
      }
case WKTKeywords.ellipsoidal:
{
      if (defaultUnit == null) {
        throw parent.missingComponent(WKTKeywords.AngleUnit);
      }
      if (isWKT1) {
        nx=AxisNames.GEODETIC_LONGITUDE;
        x="String_Node_Str";
        ny=AxisNames.GEODETIC_LATITUDE;
        y="String_Node_Str";
      }
 else {
        nx=AxisNames.GEODETIC_LATITUDE;
        x="String_Node_Str";
        dx=AxisDirection.NORTH;
        ny=AxisNames.GEODETIC_LONGITUDE;
        y="String_Node_Str";
        dy=AxisDirection.EAST;
      }
      if (dimension >= 3) {
        direction=AxisDirection.UP;
        z="String_Node_Str";
        nz=AxisNames.ELLIPSOIDAL_HEIGHT;
        unit=SI.METRE;
      }
      break;
    }
case WKTKeywords.vertical:
{
    if (defaultUnit == null) {
      throw parent.missingComponent(WKTKeywords.Unit);
    }
    z="String_Node_Str";
    nz="String_Node_Str";
    direction=AxisDirection.UP;
    if (datum instanceof VerticalDatum) {
      final VerticalDatumType vt=((VerticalDatum)datum).getVerticalDatumType();
      if (VerticalDatumType.GEOIDAL.equals(vt)) {
        nz=AxisNames.GRAVITY_RELATED_HEIGHT;
        z="String_Node_Str";
      }
 else       if (VerticalDatumType.DEPTH.equals(vt)) {
        direction=AxisDirection.DOWN;
        nz=AxisNames.DEPTH;
        z="String_Node_Str";
      }
 else       if (VerticalDatumTypes.ELLIPSOIDAL.equals(vt)) {
        nz=AxisNames.ELLIPSOIDAL_HEIGHT;
      }
    }
    break;
  }
case WKTKeywords.temporal:
{
  if (defaultUnit == null) {
    throw parent.missingComponent(WKTKeywords.TimeUnit);
  }
  direction=AxisDirection.FUTURE;
  nz="String_Node_Str";
  z="String_Node_Str";
  break;
}
default :
{
throw parent.missingComponent(WKTKeywords.Axis);
}
}
int i=0;
axes=new CoordinateSystemAxis[dimension];
if (x != null && i < dimension) axes[i++]=csFactory.createCoordinateSystemAxis(singletonMap(CoordinateSystemAxis.NAME_KEY,nx),x,dx,defaultUnit);
if (y != null && i < dimension) axes[i++]=csFactory.createCoordinateSystemAxis(singletonMap(CoordinateSystemAxis.NAME_KEY,ny),y,dy,defaultUnit);
if (z != null && i < dimension) axes[i++]=csFactory.createCoordinateSystemAxis(singletonMap(CoordinateSystemAxis.NAME_KEY,nz),z,direction,unit);
}
final String name;
{
final StringBuilder buffer=new StringBuilder();
if (type != null && !type.isEmpty()) {
final int c=type.codePointAt(0);
buffer.appendCodePoint(Character.toUpperCase(c)).append(type,Character.charCount(c),type.length()).append(' ');
}
name=AxisDirections.appendTo(buffer.append("String_Node_Str"),axes);
}
if (csProperties == null) {
csProperties=singletonMap(CoordinateSystem.NAME_KEY,name);
}
 else {
csProperties.put(CoordinateSystem.NAME_KEY,name);
}
if (type == null) {
return referencing.createAbstractCS(csProperties,axes);
}
switch (type) {
case WKTKeywords.ellipsoidal:
{
switch (axes.length) {
case 2:
return csFactory.createEllipsoidalCS(csProperties,axes[0],axes[1]);
case 3:
return csFactory.createEllipsoidalCS(csProperties,axes[0],axes[1],axes[2]);
}
dimension=(axes.length < 2) ? 2 : 3;
break;
}
case WKTKeywords.Cartesian:
{
switch (axes.length) {
case 2:
return csFactory.createCartesianCS(csProperties,axes[0],axes[1]);
case 3:
return csFactory.createCartesianCS(csProperties,axes[0],axes[1],axes[2]);
}
dimension=(axes.length < 2) ? 2 : 3;
break;
}
case WKTKeywords.affine:
{
switch (axes.length) {
case 2:
return csFactory.createAffineCS(csProperties,axes[0],axes[1]);
case 3:
return csFactory.createAffineCS(csProperties,axes[0],axes[1],axes[2]);
}
dimension=(axes.length < 2) ? 2 : 3;
break;
}
case WKTKeywords.vertical:
{
if (axes.length != (dimension=1)) break;
return csFactory.createVerticalCS(csProperties,axes[0]);
}
case WKTKeywords.temporal:
{
if (axes.length != (dimension=1)) break;
return csFactory.createTimeCS(csProperties,axes[0]);
}
case WKTKeywords.linear:
{
if (axes.length != (dimension=1)) break;
return csFactory.createLinearCS(csProperties,axes[0]);
}
case WKTKeywords.polar:
{
if (axes.length != (dimension=2)) break;
return csFactory.createPolarCS(csProperties,axes[0],axes[1]);
}
case WKTKeywords.cylindrical:
{
if (axes.length != (dimension=3)) break;
return csFactory.createCylindricalCS(csProperties,axes[0],axes[1],axes[2]);
}
case WKTKeywords.spherical:
{
if (axes.length != (dimension=3)) break;
return csFactory.createSphericalCS(csProperties,axes[0],axes[1],axes[2]);
}
case WKTKeywords.parametric:
{
return referencing.createAbstractCS(csProperties,axes);
}
default :
{
warning(parent,null,Errors.formatInternational(Errors.Keys.UnknownType_1,type),null);
return referencing.createAbstractCS(csProperties,axes);
}
}
throw new LocalizedParseException(errorLocale,(axes.length > dimension) ? Errors.Keys.TooManyOccurrences_2 : Errors.Keys.TooFewOccurrences_2,new Object[]{dimension,WKTKeywords.Axis},parent.offset);
}