unit pnginputstream;
//
//  Title:  PNG Input File Stream
//
//  Copyright 1999, 2001 Colosseum Builders, Inc.
//  All rights reserved.
//
//  Colosseum Builders, Inc. makes no warranty, expressed or implied
//  with regards to this software. It is provided as is.
//
//  Author:  John M. Miano (miano@colosseumbuilders.com)
//
//  Date:    March 15, 1999
//
//  Version: 1
//
//  Description:
//
//    This class is a PNG input stream attached to a file.
//

interface

uses sysutils, inflateinputstream ;

Type

  TPngInputStream = Class (TInflateInputStream)
    Protected
      chunk_type : String ;
      chunk_data : Pointer ;
      chunk_length : Cardinal ;
      Procedure fillBuffer ; Override ;
      Function readChunkLength : Cardinal ; Virtual ; Abstract ;
      Function readChunkData (length : Cardinal) : Pointer ; Virtual ; Abstract ;
      Function readCrc : Cardinal ; Virtual ; Abstract ;
    Public
      Function getNextChunk : Boolean ;
      Property ChunkType : String Read chunk_type ;
      Property ChunkDataLength : Cardinal Read chunk_length ;
      Property ChunkData : Pointer read chunk_data ;
      Procedure readRaw (count : Cardinal ; var buffer : String) ; Virtual ; Abstract ;
    End ;

  EStreamError = Class (Exception) ;


implementation

Uses
  crc32 ;

Function TPngInputStream.getNextChunk : Boolean ;
  Var
    filecrc : Cardinal ;
    crc : TCrc32 ;
    crcvalue : Cardinal ;
    chunktype : PCHAR ;
  Begin
  Result := false ;
  chunk_length := readChunkLength ;
//###  if (chunk_length = 0) Then
//###    Exit ;

  chunk_data := readChunkData (chunk_length + sizeof (chunk_length)) ;
  filecrc := readCrc ;
  crc := Tcrc32.Create ;
  Try
    crc.update (chunk_data, chunk_length + sizeof (chunk_length)) ;
    crcvalue := crc.value ;
    if (filecrc <> crcvalue) Then
      Raise EStreamError.Create ('Invalid Chunk CRC') ;
  Finally
    crc.Destroy ;
    End ;

  chunktype := chunk_data ;
  SetLength (chunk_type, 4) ;
  chunk_type [1] := chunktype^ ; Inc (chunktype) ;
  chunk_type [2] := chunktype^ ; Inc (chunktype) ;
  chunk_type [3] := chunktype^ ; Inc (chunktype) ;
  chunk_type [4] := chunktype^ ; Inc (chunktype) ;
  chunk_data := chunktype ;

  current_byte := chunk_data ;
  buffer_limit := @chunktype [chunk_length] ;
  Result := True ;
  End ;

Procedure TPngInputStream.fillBuffer ;
  Begin
  if (Not getNextChunk) Then
    Raise EStreamError.Create ('Premature End of File') ;
  if (chunk_type <> 'IDAT') then
    Raise EStreamError.Create ('Missing IDAT Chunk') ;
  current_byte := chunk_data ;
  buffer_limit := @current_byte [chunk_length] ;
  End ;



end.
