/*
* Copyright 2016 Skynav, Inc. All rights reserved.
* Portions Copyright 2009 Extensible Formatting Systems, Inc (XFSI).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY SKYNAV, INC. AND ITS CONTRIBUTORS “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL SKYNAV, INC. OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.xfsi.xav.validation.images.jpeg;
import java.io.EOFException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import com.xfsi.xav.validation.images.jpeg.JpegValidator.MsgCode;
import com.xfsi.xav.validation.util.AbstractLoggingValidator;
/**
* validates SOS segment
*/
class SegmentParserFFDA extends SegmentParser {
boolean validate(JpegInputStream jis, JpegState js, AbstractLoggingValidator mh) throws EOFException
{
try
{
js.incrementSosSegmentCount();
if (js.getInitialFrameCode() == null)
mh.logResult(JpegValidator.MsgCode.JPG01E024, js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I031, js.getSegmentCount(), js.getInitialFrameCode());
short segmentBytesLeft = jis.readShort();
int nS = jis.readByte() & 0xff;
int expectedNs = 6 + (2*nS);
if (segmentBytesLeft != expectedNs)
mh.logResult(JpegValidator.MsgCode.JPG01E025, segmentBytesLeft, expectedNs, js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I032, segmentBytesLeft, js.getSegmentCount());
List<Integer> valid = getExpectedNsValues(js);
if (valid != null)
{
if(!valid.contains(nS))
mh.logResult(JpegValidator.MsgCode.JPG01E026, nS, valid, js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I033, nS, js.getSegmentCount());
}
List<Integer> validTd = getExpectedTdValues(js);
List<Integer> validTa = getExpectedTaValues(js);
int value;
for (int j = 0; j < nS; j++)
{
jis.readByte(); // Cs(j) can range from 0-255, nothing to check //TODO: check that it's a member of Ci specified in SOFn
value = jis.readByte() & 0xff;
int tD = (value & 0xf) >>> 4;
int tA = (value & 0xf);
if (validTd != null)
{
if (!validTd.contains(tD))
mh.logResult(JpegValidator.MsgCode.JPG01E027, j, tD, validTd, js.getFrameType().toString(), js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I034, j, tD, js.getFrameType().toString(), js.getSegmentCount());
}
if (validTa != null)
{
if (!validTa.contains(tA))
mh.logResult(JpegValidator.MsgCode.JPG01E028, j, tA, validTa, js.getFrameType().toString(), js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I035, j, tA, js.getFrameType().toString(), js.getSegmentCount());
}
}
int sS = jis.readByte() & 0xff;
valid = getExpectedSsValues(js);
if (valid != null)
{
if (!valid.contains(sS))
mh.logResult(JpegValidator.MsgCode.JPG01E029, sS, valid, js.getFrameType().toString(), js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I036, sS, js.getFrameType().toString(), js.getSegmentCount());
}
int sE = jis.readByte() & 0xff;
valid = getExpectedSeValues(js, sS);
if (valid != null)
{
if (!valid.contains(sE))
mh.logResult(JpegValidator.MsgCode.JPG01E030, sE, valid, js.getFrameType().toString(), js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I037, sE, js.getFrameType().toString(), js.getSegmentCount());
}
value = jis.readByte() & 0xff;
int aH = (value & 0xf) >>> 4;
int aL = (value & 0xf);
valid = getExpectedAhValues(js);
if (valid != null)
{
if (!valid.contains(aH))
mh.logResult(JpegValidator.MsgCode.JPG01E031, aH, valid, js.getFrameType().toString(), js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I038, aH, js.getFrameType().toString(), js.getSegmentCount());
}
valid = getExpectedAlValues(js);
if (valid != null)
{
if (!valid.contains(aL))
mh.logResult(JpegValidator.MsgCode.JPG01E032, aL, valid, js.getFrameType().toString(), js.getSegmentCount());
else
mh.logResult(JpegValidator.MsgCode.JPG01I039, aL, js.getFrameType().toString(), js.getSegmentCount());
}
parseScanData(jis, js, mh);
}
catch (EOFException e)
{
mh.logResult(JpegValidator.MsgCode.JPG01F003, js.getCurrentCode(), js.getSegmentCount(), jis.getTotalBytesRead());
throw e;
}
catch (IOException e)
{
assert(false) : mh.msgFormatterNV(MsgCode.JPG01X003.toString(), Thread.currentThread().getStackTrace()[2].getMethodName(), e.getMessage());
}
return true;
}
private void parseScanData(JpegInputStream jis, JpegState js, AbstractLoggingValidator mh) throws EOFException, IOException
{
int count = 0;
while (true)
{
int b = jis.readByte() & 0xff;
if (b == 0xff)
{
do
{
b = jis.readByte() & 0xff;
} while (b == 0xff);
if (b != 0)
{
if (b >= 0xd0 && b <= 0xd7)
{
js.setCurrentCode((short) (0xff << 8 | b));
js.incrementTablesMiscSegmentCount();
mh.logResult(JpegValidator.MsgCode.JPG01I030, js.getCurrentCode());
}
else
{
if (count == 0)
mh.logResult(JpegValidator.MsgCode.JPG01E013, js.getSegmentCount(), jis.getTotalBytesRead());
if (js.getSosSegmentCount() == 1 && b == 0xdc)
js.allowDnlSegment();
jis.putBack((byte) 0xff);
jis.putBack((byte) b);
break; // next marker tag found
}
}
count++;
}
count++;
}
}
private List<Integer> getExpectedNsValues(JpegState js)
{
List<Integer> values = null;
if (js.getFrameType() != null)
{
values = new LinkedList<Integer>();
for (int i = 1; i <= 4; i++)
values.add(i);
}
return values;
}
private List<Integer> getExpectedTdValues(JpegState js)
{
List<Integer> values = null;
if (js.getFrameType() != null)
{
values = new LinkedList<Integer>();
switch (js.getFrameType())
{
case BASELINE:
for (int i = 0; i <= 1; i++)
values.add(i);
break;
case EXTENDED:
case PROGRESSIVE:
case LOSSLESS:
for (int i = 0; i <= 3; i++)
values.add(i);
break;
}
}
return values;
}
private List<Integer> getExpectedTaValues(JpegState js)
{
List<Integer> values = null;
if (js.getFrameType() != null)
{
values = new LinkedList<Integer>();
switch (js.getFrameType())
{
case BASELINE:
for (int i = 0; i <= 1; i++)
values.add(i);
break;
case EXTENDED:
case PROGRESSIVE:
for (int i = 0; i <= 3; i++)
values.add(i);
break;
case LOSSLESS:
values.add(0);
break;
}
}
return values;
}
private List<Integer> getExpectedSsValues(JpegState js)
{
List<Integer> values = null;
if (js.getFrameType() != null)
{
values = new LinkedList<Integer>();
switch (js.getFrameType())
{
case BASELINE:
case EXTENDED:
values.add(0);
break;
case PROGRESSIVE:
for (int i = 0; i <= 63; i++)
values.add(i);
break;
case LOSSLESS:
for (int i = 1; i < 8; i++)
values.add(i);
break;
}
}
return values;
}
private List<Integer> getExpectedSeValues(JpegState js, int sS)
{
List<Integer> values = null;
if (js.getFrameType() != null)
{
values = new LinkedList<Integer>();
switch (js.getFrameType())
{
case BASELINE:
case EXTENDED:
values.add(63);
break;
case PROGRESSIVE:
if (sS > 63)
break; // error already detected above
for (int i = sS; i <= 63; i++)
values.add(i);
break;
case LOSSLESS:
values.add(0);
break;
}
}
return values;
}
private List<Integer> getExpectedAhValues(JpegState js)
{
List<Integer> values = null;
if (js.getFrameType() != null)
{
values = new LinkedList<Integer>();
switch (js.getFrameType())
{
case BASELINE:
case EXTENDED:
case LOSSLESS:
values.add(0);
break;
case PROGRESSIVE:
for (int i = 0; i <= 13; i++)
values.add(i);
break;
}
}
return values;
}
private List<Integer> getExpectedAlValues(JpegState js)
{
List<Integer> values = null;
if (js.getFrameType() != null)
{
values = new LinkedList<Integer>();
switch (js.getFrameType())
{
case BASELINE:
case EXTENDED:
values.add(0);
break;
case PROGRESSIVE:
for (int i = 0; i <= 13; i++)
values.add(i);
break;
case LOSSLESS:
for (int i = 0; i <= 15; i++)
values.add(i);
break;
}
}
return values;
}
}