Beispiel #1
0
/// Frame::ScanForScanHeader
// Start parsing a hidden scan, let it be either the residual or the refinement
// scan.
bool Frame::ScanForScanHeader(class ByteStream *stream)
{ 
  LONG data;

  
  //
  data = stream->GetWord();
  if (data != 0xffda) {
    JPG_WARN(MALFORMED_STREAM,"Frame::StartParseHiddenScan","Start of Scan SOS marker missing");
    // Advance to the next marker if there is something next.
    //
    do {
      stream->LastUnDo();
      do {
	data = stream->Get();
      } while(data != 0xff && data != ByteStream::EOF);
      //
      if (data == ByteStream::EOF)
	break; // Try from the main stream
      stream->LastUnDo();
      //
      // If this is SOS, we recovered. Maybe.
      data = stream->GetWord();
      if (data == ByteStream::EOF)
	break;
      // Check for the proper marker.
    } while(data != 0xffda);
  }

  return (data == 0xffda)?(true):(false);
}
Beispiel #2
0
/// Frame::PostImageHeight
// Define the image size if it is not yet known here. This is
// called whenever the DNL marker is parsed in.
void Frame::PostImageHeight(ULONG height)
{
  assert(height > 0 && m_pImage);
  
  if (m_ulHeight == 0) {
    m_ulHeight = height;
    m_pImage->PostImageHeight(height);
  } else if (m_ulHeight == height) {
    JPG_WARN(MALFORMED_STREAM,"Frame::PostImageHeight",
	     "found a double DNL marker for a frame, frame size is known already");
  } else {
    JPG_THROW(MALFORMED_STREAM,"Frame::PostImageHeight",
	      "found a double DNL marker for a frame, indicating an inconsistent frame height");
  }
}
Beispiel #3
0
  //
  // Compute the Golomb parameter from the context.
  UBYTE GolombParameter(UWORD context) const
  {
    UBYTE k;

    for(k = 0;(m_lN[context] << k) < m_lA[context] && k < 24;k++) {
    }

    if (unlikely(k == 24)) {
      JPG_WARN(MALFORMED_STREAM,"JPEGLSScan::GolombParameter",
               "Golomb coding parameter of JPEG LS stream run out of bounds, "
               "synchronization lost");
      return 0;
    }
    
    return k;
  }
Beispiel #4
0
/// DecoderStream::Append
// Given a byte stream and a size,
// attach as many bytes in the byte stream to the decoder stream.
// The bytes are read from the byte stream and feed into here.
// Returns false on error.
bool DecoderStream::Append(class ByteStream *from,ULONG read_size,ULONG index)
{
  //
  // First, check whether we provide any bytes at all. If not, bail out.
  if (read_size) {
    ULONG size;
    struct BufferNode *bn;
    // Now allocate a new buffer node of the given priority and link it in.
    bn = BufferNode::AddBuffer(m_pEnviron,m_pBufferList,index,read_size);
    // And read the data into the buffer.
    size = from->Read(bn->bn_pucBuffer,read_size);
    if (size != read_size) {
      if (size < read_size) {
        // fill the remaining part with zeros.
        memset(bn->bn_pucBuffer + size,0,read_size - size);
      }
      // Support truncated streams, but warn!
      JPG_WARN(UNEXPECTED_EOF, "DecoderStream::Append",
               "unexpected EOF on pulling encoded data");
      return false;
    }
  }
  return true;
}
Beispiel #5
0
/// Frame::ParseTrailer
// Parse off the EOI marker at the end of the image. Return false
// if there are no more scans in the file, true otherwise.
bool Frame::ParseTrailer(class ByteStream *io)
{
  do {
    LONG marker = io->PeekWord();
    
    switch(marker) {
    case 0xffc0:
    case 0xffc1:
    case 0xffc2:
    case 0xffc3:
    case 0xffc9:
    case 0xffca:
    case 0xffcb:
    case 0xfff7:
      // All non-differential frames, may not appear in a hierarchical process.
      JPG_WARN(MALFORMED_STREAM,"Frame::ParseTrailer",
	       "found a non-differential frame start behind the initial frame");
      return true;
    case 0xffd9: // The EOI still needs to be seen by the image.
    case 0xffc5:
    case 0xffc6:
    case 0xffc7:
    case 0xffcd:
    case 0xffce:  
    case 0xffcf:
    case 0xffdf: // EXP-marker also terminates this frame.
      // All differential frame starts: The frame ends here.
      // If we have a residual scan that is not yet parsed off,
      // create it now and parse it last so it sees the original
      // data. 
      if (m_pTables->RefinementDataOf() && !m_bCreatedRefinement) {
	assert(m_pImage);
	if (dynamic_cast<class BlockBitmapRequester *>(m_pImage)) {
	  LONG data;
	  do {
	    data = m_pTables->RefinementDataOf()->StreamOf()->PeekWord();
	    if (data == 0xffff) {
	      m_pTables->RefinementDataOf()->StreamOf()->Get(); // Filler byte
	    }
	  } while(data == 0xffff);
	  if (data != ByteStream::EOF && data != 0xffd9) {
	    m_bBuildRefinement = true;
	    //
	    // Come here again when the refinement is parsed off.
	    return true;
	  } else {
	    // Do not come again, refinement is there already.
	    m_bCreatedRefinement = true;
	  }
	}
      }
      if (m_pTables->ResidualDataOf() && !m_bCreatedResidual) {
	assert(m_pImage);
	if (dynamic_cast<class BlockBitmapRequester *>(m_pImage)) { 
	  LONG data;
	  do {
	    data = m_pTables->ResidualDataOf()->StreamOf()->PeekWord();
	    if (data == 0xffff) {
	      m_pTables->ResidualDataOf()->StreamOf()->Get(); // Filler byte
	    }
	  } while(data == 0xffff);
	  if (data != ByteStream::EOF && data != 0xffd9) {
	    m_bBuildResidual = true;
	    //
	    // Come here again when the residual is parsed off.
	    return true;
	  } else {
	    // Do not come again, refinement is there already.
	    m_bCreatedResidual = true;
	  }
	}
      }
      return false;
    case 0xffff:
      // A filler byte. Remove the filler, try again.
      io->Get();
      break;
    case 0xffd0:
    case 0xffd1:
    case 0xffd2:
    case 0xffd3:
    case 0xffd4:
    case 0xffd5:
    case 0xffd6:
    case 0xffd7: // Restart markers.
      io->GetWord();
      JPG_WARN(MALFORMED_STREAM,"Frame::ParseTrailer","found a stray restart marker segment, ignoring");
      break;
    case ByteStream::EOF:
      JPG_WARN(MALFORMED_STREAM,"Frame::ParseTrailer",
	       "expecting an EOI marker at the end of the stream");
      return false;
    default:
      if (marker < 0xff00) {
	JPG_WARN(MALFORMED_STREAM,"Frame::ParseTrailer",
		 "expecting a marker or marker segment - stream is out of sync");
	// Advance to the next marker and see how it goes from there...
	io->Get(); // Remove the invalid thing.
	do {
	  marker = io->Get();
	} while(marker != 0xff && marker != ByteStream::EOF);
	//
	if (marker == ByteStream::EOF) {
	  JPG_WARN(UNEXPECTED_EOF,"Frame::ParseTrailer",
		   "run into an EOF while scanning for the next marker");
	  return false;
	}
	io->LastUnDo();
	// Continue parsing, check what the next marker might be.
      } else if (marker < 0xffc0) {
	JPG_WARN(MALFORMED_STREAM,"Frame::ParseTrailer",
		 "detected an unknown marker - stream is out of sync");
	return true;
      } else {
	return true;
      }
    }
  } while(true);
  return true; // code never goes here.
}
Beispiel #6
0
/// Tables::ParseTables
// Parse off tables, including an application marker,
// comment, huffman tables or quantization tables.
// Returns on the first unknown marker.
void Tables::ParseTables(class ByteStream *io)
{
  do {
    LONG marker = io->PeekWord();
    switch(marker) {
    case 0xffdb: // DQT
      io->GetWord();
      if (m_pQuant == NULL)
	m_pQuant = new(m_pEnviron) Quantization(m_pEnviron);
      m_pQuant->ParseMarker(io);
      break;
    case 0xffc4: // DHT 
      io->GetWord();
      if (m_pHuffman == NULL)
	m_pHuffman = new(m_pEnviron) HuffmanTable(m_pEnviron);
      m_pHuffman->ParseMarker(io);
      break;
    case 0xffcc: // DAC
      io->GetWord();
      if (m_pConditioner == NULL)
	m_pConditioner = new(m_pEnviron) class ACTable(m_pEnviron);
      m_pConditioner->ParseMarker(io);
      break;
    case 0xffdd: // DRI
      io->GetWord();
      if (m_pRestart == NULL)
	m_pRestart = new(m_pEnviron) class RestartIntervalMarker(m_pEnviron);
      m_pRestart->ParseMarker(io);
      break;
    case 0xfffe: // COM
      {
	LONG size; 
	io->GetWord();
	size = io->GetWord();
	// Application marker.
	if (size == ByteStream::EOF)
	  JPG_THROW(UNEXPECTED_EOF,"Tables::ParseTables","COM marker incomplete, stream truncated");
	//
	if (size <= 0x02)
	  JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables","COM marker size out of range");
	//
	// Just skip the contents. For now. More later on.
	io->SkipBytes(size - 2);
      }
      break; 
    case 0xfff8: // LSE: JPEG LS extensions marker.
      {
	io->GetWord();
	LONG len = io->GetWord();
	if (len > 3) {
	  UBYTE id = io->Get();
	  if (id == 1) {
	    // Thresholds marker.
	    if (m_pThresholds == NULL)
	      m_pThresholds = new(m_pEnviron) class Thresholds(m_pEnviron);
	    m_pThresholds->ParseMarker(io,len);
	    break;
	  } else if (id == 2 || id == 3) {
	    JPG_THROW(NOT_IMPLEMENTED,"Tables::ParseTables",
		      "JPEG LS mapping tables are not implemented by this code, sorry");
	  } else if (id == 4) {
	    JPG_THROW(NOT_IMPLEMENTED,"Tables::ParseTables",
		      "JPEG LS size extensions are not implemented by this code, sorry");
	  } else if (id == 0x0d) {
	    // LS Reversible Color transformation
	    if (m_pLSColorTrafo)
	      JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables",
			"found duplicate JPEG LS color transformation specification");
	    m_pLSColorTrafo = new(m_pEnviron) class LSColorTrafo(m_pEnviron);
	    m_pLSColorTrafo->ParseMarker(io,len);
	    break;
	  } else {
	    JPG_WARN(NOT_IMPLEMENTED,"Tables::ParseMarker",
		     "skipping over unknown JPEG LS extensions marker");
	  }
	}
	if (len <= 0x02)
	  JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables","marker size out of range");
	//
	// Just skip the contents. For now. More later on.
	io->SkipBytes(len - 2);
      }
      break;
    case 0xffe0: // APP0: Maybe the JFIF marker.
      {
	io->GetWord();
	LONG len = io->GetWord();
	if (len >= 2 + 5 + 2 + 1 + 2 + 2 + 1 + 1) { 
	  const char *id = "JFIF";
	  while(*id) {
	    len--;
	    if (io->Get() != *id)
	      break;
	    id++;
	  }
	  if (*id == 0) {
	    len--;
	    if (io->Get() == 0) {
	      if (m_pResolutionInfo == NULL)
		m_pResolutionInfo = new(m_pEnviron) class JFIFMarker(m_pEnviron);
	      m_pResolutionInfo->ParseMarker(io,len + 5);
	      break;
	    }
	  }
	}
	if (len <= 0x02)
	  JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables","marker size out of range");
	//
	// Just skip the contents. For now. More later on.
	io->SkipBytes(len - 2);
      }
      break;  
    case 0xffe1: // APP1: Maybe the EXIF marker.
      {
	io->GetWord();
	LONG len = io->GetWord();
	if (len >= 2 + 4 + 2 + 2 + 2 + 4 + 2) { 
	  const char *id = "Exif";
	  while(*id) {
	    len--;
	    if (io->Get() != *id)
	      break;
	    id++;
	  }
	  if (*id == 0) {
	    len -= 2;
	    if (io->GetWord() == 0) {
	      if (m_pCameraInfo == NULL)
		m_pCameraInfo = new(m_pEnviron) class EXIFMarker(m_pEnviron);
	      m_pCameraInfo->ParseMarker(io,len + 4 + 2);
	      break;
	    }
	  }
	}
	if (len <= 0x02)
	  JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables","marker size out of range");
	//
	// Just skip the contents. For now. More later on.
	io->SkipBytes(len - 2);
      }
      break;
    case 0xffe9: // APP9:  Application markers defined here.
      {
	UWORD len;
	io->GetWord();
	len = io->GetWord();
	if (len > 2 + 2 + 4) {
	  UWORD id = io->GetWord();
	  if (id == (('J' << 8) | ('P'))) {
	    LONG type = io->GetWord() << 16;
	    type |= io->GetWord();
	    if (type == JPG_MAKEID('S','E','R','M')) {
	      if (m_pLosslessMarker == NULL)
		m_pLosslessMarker = new(m_pEnviron) class LosslessMarker(m_pEnviron);
	      m_pLosslessMarker->ParseMarker(io,len);
	      if (m_bForceFixpoint) {
		delete m_pLosslessMarker;m_pLosslessMarker = NULL;
	      }
	      break;
	    } else if (type == JPG_MAKEID('R','E','S','I')) {
	      if (m_pResidualData == NULL)
		m_pResidualData = new(m_pEnviron) class ResidualMarker(m_pEnviron,
								       ResidualMarker::Residual);
	      //
	      // Parse off the residual data.
	      m_pResidualData->ParseMarker(io,len);
	      break;
	    } else if (type == JPG_MAKEID('F','I','N','E')) {
	      if (m_pRefinementData == NULL)
		m_pRefinementData = new(m_pEnviron) class ResidualMarker(m_pEnviron,
									 ResidualMarker::Refinement);
	      //
	      m_pRefinementData->ParseMarker(io,len);
	      break;
	    } else if (type == JPG_MAKEID('S','P','E','C')) {
	      if (m_pResidualSpecs == NULL)
		m_pResidualSpecs = new(m_pEnviron) class ResidualSpecsMarker(m_pEnviron);
	      //
	      // Parse off the residual specifications.
	      m_pResidualSpecs->ParseMarker(io,len);
	      break;
	    } else if (type == JPG_MAKEID('T','O','N','E')) {
	      class ToneMappingMarker *tone = new(m_pEnviron) class ToneMappingMarker(m_pEnviron);
	      //
	      // Append to the end of the list.
	      tone->NextOf()       = m_pToneMappingMarker;
	      m_pToneMappingMarker = tone;
	      //
	      // Parse the stuff off.
	      tone->ParseMarker(io,len);
	      break;
	    }
	    len -= 2 + 4; // bytes already read.
	  } else {
	    len -= 2;
	  }
	}
	if (len <= 0x02)
	  JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables","marker size out of range");
	//
	// Just skip the contents. For now. More later on.
	io->SkipBytes(len - 2);
      }
      break;
    case 0xffee: // APP14: Maybe the adobe marker.
      {
	io->GetWord();
	LONG len = io->GetWord();
	if (len == 2 + 5 + 2 + 2 + 2 + 1) { 
	  const char *id = "Adobe";
	  while(*id) {
	    len--;
	    if (io->Get() != *id)
	      break;
	    id++;
	  }
	  if (*id == 0) {
	    if (m_pColorInfo == NULL)
	      m_pColorInfo = new(m_pEnviron) class AdobeMarker(m_pEnviron);
	    m_pColorInfo->ParseMarker(io,len + 5);
	    break;
	  }
	}
	if (len <= 0x02)
	  JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables","marker size out of range");
	//
	// Just skip the contents. For now. More later on.
	io->SkipBytes(len - 2);
      }
      break;
    case 0xffc0:
    case 0xffc1:
    case 0xffc2:
    case 0xffc3:
    case 0xffc5:
    case 0xffc6:
    case 0xffc7:
    case 0xffc8:
    case 0xffc9:
    case 0xffca:
    case 0xffcb:
    case 0xffcd:
    case 0xffce:
    case 0xffcf: // all start of frame markers.
    case 0xffda: // Start of scan.
    case 0xffde: // DHP
    case 0xfff7: // JPEG LS SOS
      return;
    case 0xffff: // A filler byte followed by a marker. Skip.
      io->Get();
      break;
    case 0xffd0:
    case 0xffd1:
    case 0xffd2:
    case 0xffd3:
    case 0xffd4:
    case 0xffd5:
    case 0xffd6:
    case 0xffd7: // Restart markers.
      io->GetWord();
      JPG_WARN(MALFORMED_STREAM,"Tables::ParseTables","found a stray restart marker segment, ignoring");
      break;
    default: 
      if (marker >= 0xffc0 && (marker < 0xffd0 || marker >= 0xffd8) && marker < 0xfff0) {
	LONG size;
	io->GetWord();
	size = io->GetWord();
	// Application marker.
	if (size == ByteStream::EOF)
	  JPG_THROW(UNEXPECTED_EOF,"Tables::ParseTables","marker incomplete, stream truncated");
	//
	if (size <= 0x02)
	  JPG_THROW(MALFORMED_STREAM,"Tables::ParseTables","marker size out of range");
	//
	// Just skip the contents. For now. More later on.
	io->SkipBytes(size - 2);
      } else {
	LONG dt;
	//
	JPG_WARN(MALFORMED_STREAM,"Tables::ParseTables",
		 "found invalid marker, probably a marker size is out of range");
	// Advance to the next marker manually.
	io->Get();
	do {
	  dt = io->Get();
	} while(dt != 0xff && dt != ByteStream::EOF);
	//
	if (dt == 0xff) {
	  io->LastUnDo();
	} else {
	  return;
	}
      }
    }
  } while(true);
}
Beispiel #7
0
/// EntropyParser::ParseRestartMarker
// Parse the restart marker or resync at the restart marker.
void EntropyParser::ParseRestartMarker(class ByteStream *io)
{
  LONG dt = io->PeekWord();
  
  while(dt == 0xffff) {
    // Found a filler byte. Skip over and try again.
    io->Get();
    dt = io->PeekWord();
  }
  
  if (dt == 0xffdc && m_bScanForDNL) {
    ParseDNLMarker(io);
  } else if (dt == m_usNextRestartMarker) {
    // Everything worked fine! Continue going after removing the marker.
    io->GetWord();
    Restart();
    m_usNextRestartMarker = (m_usNextRestartMarker + 1) & 0xfff7;
    m_usMCUsToGo          = m_usRestartInterval;
    m_bSegmentIsValid     = true;
  } else {
    JPG_WARN(MALFORMED_STREAM,"EntropyParser::ParseRestartMarker",
             "entropy coder is out of sync, trying to advance to the next marker");
    // As said...
    //
    do {
      dt = io->Get();
      if (dt == ByteStream::EOF) {
        // Outch, run completely out of data.
        JPG_THROW(UNEXPECTED_EOF,"EntropyParser::ParseRestartMarker",
                  "run into end of file while trying to resync the entropy parser");
        //
        // Code never goes here...
        return;
      } else if (dt == 0xff) {
        // Could be a marker.
        io->LastUnDo();
        dt = io->PeekWord();
        // Depends now on the marker.
        if (dt >= 0xffd0 && dt < 0xffd8) {
          // Is a restart marker. If this is the correct one, just leave,
          // the entropy coder was behind and we are then again up at the
          // correct index.
          if (dt == m_usNextRestartMarker) {
            io->GetWord();
            Restart();
            m_usNextRestartMarker = (m_usNextRestartMarker + 1) & 0xfff7;
            m_usMCUsToGo          = m_usRestartInterval;
            m_bSegmentIsValid     = true;
            return;
          } else if (((dt - m_usNextRestartMarker) & 0x07) >= 4) {
            // Here dt is *likely* behind, i.e. we need to skip more
            // data to advance to the correct restart marker.
            io->GetWord();
            // Remove the marker and keep going.
          } else {
            // Here dt is likely ahead, that is, the entropy decoder
            // should better skip the next entropy coded segment
            // completely and then should re-enter to re-examine whether
            // the marker fits. Keep the marker in the stream, then, but
            // do not continue to decode.
            m_bSegmentIsValid     = false;
            m_usNextRestartMarker = (m_usNextRestartMarker + 1) & 0xfff7;
            m_usMCUsToGo          = m_usRestartInterval;
            // Do not run into a restart as this may pull bytes.
            return;
          }
        } else if (dt >= 0xffc0 && dt < 0xfff0) {
          // Is apparently some other marker, i.e. we are at the end of
          // the segment. Continue skipping until the end is reached and
          // the parser run out of fun...
          m_bSegmentIsValid     = false;
          m_usNextRestartMarker = (m_usNextRestartMarker + 1) & 0xfff7;
          m_usMCUsToGo          = m_usRestartInterval;
          // Do not run into a restart as this may pull bytes.
          return;
        } else {
          // Some garbadge data, or a 0xff00. Just eat it up, and continue
          // scanning. Note that a single Get is used here to eventually
          // skip over a "fill byte".
          io->Get();
        }
      }
    } while(true);
  }
}