//----------------------------------------------------------------------------
// Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
//                                and Clark Cooper
// Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers.
//
// Expat - Version 2.0.0 Release Milano 0.83 (PasExpat 2.0.0 RM0.83)
// Pascal Port By: Milan Marusinec alias Milano
//                 milan@marusinec.sk
//                 http://www.pasports.org/pasexpat
// Copyright (c) 2006
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// [Pascal Port History] -----------------------------------------------------
//
// 03.05.2006-Milano: Unit port establishment
// 02.06.2006-Milano: porting
// 06.06.2006-Milano: -"-
// 07.06.2006-Milano: doProlog
// 08.06.2006-Milano: doProlog finished, porting
// 09.06.2006-Milano: porting
// 12.06.2006-Milano: -"-
// 14.06.2006-Milano: -"-
// 15.06.2006-Milano: doContent
// 16.06.2006-Milano: porting, storeAtts
// 17.06.2006-Milano: -"-
// 20.06.2006-Milano: epilogProcessor, porting
// 22.06.2006-Milano: appendAttributeValue
//
{ xmlparse.inc }
{$Q- }
{$R- }
function  poolStoreString(pool : STRING_POOL_ptr; enc : ENCODING_ptr; ptr ,end_ : char_ptr ) : XML_Char_ptr; forward;
procedure poolFinish     (pool : STRING_POOL_ptr ); forward;
procedure poolClear      (pool : STRING_POOL_ptr ); forward;
procedure poolDestroy    (pool : STRING_POOL_ptr ); forward;
function  poolAppendChar (pool : STRING_POOL_ptr; c : char ) : int; forward;

function  reportProcessingInstruction(parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr ) : int; forward;
function  reportComment              (parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr ) : int; forward;

function  getAttributeId(parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr ) : ATTRIBUTE_ID_ptr; forward;

function  storeAttributeValue(
           parser : XML_Parser; enc : ENCODING_ptr; isCdata : XML_Bool;
           ptr ,end_ : char_ptr; pool : STRING_POOL_ptr ) : XML_Error; forward;

const
 implicitContext : array[0..40 ] of XML_Char = (
  'x' ,'m' ,'l' ,'=' ,'h' ,'t' ,'t' ,'p' ,':' ,'/' ,'/' ,
  'w' ,'w' ,'w' ,'.' ,'w' ,'3' ,'.' ,'o' ,'r' ,'g' ,'/' ,
  'X' ,'M' ,'L' ,'/' ,'1' ,'9' ,'9' ,'8' ,'/' ,
  'n' ,'a' ,'m' ,'e' ,'s' ,'p' ,'a' ,'c' ,'e' ,#0 );

 INIT_TAG_BUF_SIZE  = 32; { must be a multiple of sizeof(XML_Char) }
 INIT_DATA_BUF_SIZE = 1024;
 INIT_ATTS_SIZE     = 16;
 INIT_ATTS_VERSION  = $FFFFFFFF;
 INIT_BLOCK_SIZE    = 1024;
 INIT_BUFFER_SIZE   = 1024;

 EXPAND_SPARE = 24;

 INIT_SCAFFOLD_ELEMENTS = 32;

 INIT_POWER = 6;

type
 ICHAR_ptr_ptr = ^ICHAR_ptr;
 ICHAR_ptr = ^ICHAR;

{$IFDEF XML_UNICODE }
 ICHAR = int16u;

{$ELSE }
 ICHAR = char;

{$ENDIF }

 HASH_TABLE_ITER_ptr = ^HASH_TABLE_ITER;
 HASH_TABLE_ITER = record
   p    ,
   end_ : NAMED_ptr_ptr;

  end;

const
{$IFDEF XML_UNICODE }
 XML_ENCODE_MAX = XML_UTF16_ENCODE_MAX;

{$ELSE }
 XML_ENCODE_MAX = XML_UTF8_ENCODE_MAX;

{$ENDIF }

{ memcmp }
function  memcmp(p1 ,p2 : int8u_ptr; l : int ) : int;
begin
 while l > 0 do
  begin
   if p1^ <> p2^ then
    begin
     result:=p1^ - p2^;

     exit;

    end;

   dec(l );
   inc(ptrcomp(p1 ) );
   inc(ptrcomp(p2 ) );

  end;

 result:=0;

end;

{ CHAR_HASH }
{ Basic character hash algorithm, taken from Python's string hash:
  h = h * 1000003 ^ character, the constant being a prime number. }
function CHAR_HASH(h : int32u; c : XML_Char ) : int32u;
begin
{$IFDEF XML_UNICODE }
 result:=(h * $F4243 ) xor int16u(c );

{$ELSE }
 result:=(h * $F4243 ) xor int8u(c );

{$ENDIF }

end;

{ MUST_CONVERT }
function MUST_CONVERT(enc : ENCODING_ptr; s : char_ptr ) : int;
begin
{$IFDEF XML_UNICODE }
 result:=
  int(
   not boolean(enc.isUtf16 ) or
   boolean(int32u(s ) and 1 ) );

{$ELSE }
 result:=int(not boolean(enc.isUtf8 ) );

{$ENDIF }

end;

{ For probing (after a collision) we need a step size relative prime
  to the hash table size, which is a power of 2. We use double-hashing,
  since we can calculate a second hash value cheaply by taking those bits
  of the first hash value that were discarded (masked out) when the table
  index was calculated: index:=hash and mask, where mask:=table.size - 1.
  We limit the maximum step size to table.size div 4 (mask shr 2 ) and make
  it odd, since odd numbers are always relative prime to a power of 2. }
{ SECOND_HASH }
function SECOND_HASH(hash ,mask : int32u; power : int8u ) : int8u;
begin
 result:=((hash and not mask ) shr (power - 1 ) ) and (mask shr 2 );

end;

{ PROBE_STEP }
function PROBE_STEP(hash ,mask : int32u; power : int8u ) : int8u;
begin
 result:=SECOND_HASH(hash, mask, power) or 1;

end;

{ XML_T }
function XML_T(x : char ) : XML_Char;
begin
 result:=x;

end;

{ XML_L }
function XML_L(x : char ) : XML_Char;
begin
 result:=x;

end;

{ ROUND_UP }
{ Round up n to be a multiple of sz, where sz is a power of 2. }
function ROUND_UP(n ,sz : int ) : int;
begin
 result:=(n + (sz - 1 ) ) and not(sz - 1 );

end;

{ XmlConvert }
procedure XmlConvert(enc : ENCODING_ptr; fromP ,fromLim ,toP ,toLim : pointer );
begin
{$IFDEF XML_UNICODE }
 XmlUtf16Convert(enc ,fromP ,fromLim ,toP ,toLim );

{$ELSE }
 XmlUtf8Convert(enc ,fromP ,fromLim ,toP ,toLim );

{$ENDIF }

end;

{ XmlEncode }
function XmlEncode(charNumber : int; buf : pointer ) : int;
begin
{$IFDEF XML_UNICODE }
 result:=XmlUtf16Encode(charNumber ,buf );

{$ELSE }
 result:=XmlUtf8Encode(charNumber ,buf );

{$ENDIF }

end;

{ poolInit }
procedure poolInit(pool : STRING_POOL_ptr; ms : XML_Memory_Handling_Suite_ptr );
begin
 pool.blocks    :=NIL;
 pool.freeBlocks:=NIL;
 pool.start     :=NIL;
 pool.ptr       :=NIL;
 pool.end_      :=NIL;
 pool.mem       :=ms;

end;

{ hashTableDestroy }
procedure hashTableDestroy(table : HASH_TABLE_ptr );
var
 i : size_t;

begin
 i:=0;

 while i < table.size do
  begin
   if NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^ <> NIL then
    table.mem.free_fcn(
     pointer(NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^ ) ,
     NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^^.alloc );

   inc(i );

  end;

 table.mem.free_fcn(pointer(table.v ) ,table.a );

end;

{ hashTableInit }
procedure hashTableInit(p : HASH_TABLE_ptr; ms : XML_Memory_Handling_Suite_ptr );
begin
 p.power:=0;
 p.size :=0;
 p.used :=0;
 p.v    :=NIL;
 p.mem  :=ms;

end;

{ hashTableIterInit }
procedure hashTableIterInit(iter : HASH_TABLE_ITER_ptr; table : HASH_TABLE_ptr );
begin
 iter.p   :=table.v;
 iter.end_:=NAMED_ptr_ptr(ptrcomp(iter.p ) + table.size * sizeof(NAMED_ptr ) );

end;

{ hashTableIterNext }
function hashTableIterNext(iter : HASH_TABLE_ITER_ptr ) : NAMED_ptr;
var
 tem : NAMED_ptr;

begin
 while iter.p <> iter.end_ do
  begin
   tem:=iter.p^;

   inc(ptrcomp(iter.p ) ,sizeof(NAMED_ptr ) );

   if tem <> NIL then
    begin
     result:=tem;

     exit;

    end;

  end;

 result:=NIL;

end;

{ dtdCreate }
function dtdCreate(ms : XML_Memory_Handling_Suite_ptr ) : DTD_ptr;
var
 p : DTD_ptr;

begin
 p:=nil;
 ms.malloc_fcn(pointer(p ) ,sizeof(DTD ) );

 if p = NIL then
  begin
   result:=p;

   exit;

  end;

 poolInit(@p.pool ,ms );
 poolInit(@p.entityValuePool ,ms );

 hashTableInit(@p.generalEntities ,ms );
 hashTableInit(@p.elementTypes ,ms );
 hashTableInit(@p.attributeIds ,ms );
 hashTableInit(@p.prefixes ,ms );

{$IFDEF XML_DTD }
 p.paramEntityRead:=XML_FALSE;

 hashTableInit(@p.paramEntities ,ms );

{$ENDIF }

 p.defaultPrefix.name   :=NIL;
 p.defaultPrefix.binding:=NIL;

 p.in_eldecl       :=XML_FALSE;
 p.scaffIndex      :=NIL;
 p.scaffAlloc      :=0;
 p.scaffold        :=NIL;
 p.scaffLevel      :=0;
 p.scaffSize       :=0;
 p.scaffCount      :=0;
 p.contentStringLen:=0;

 p.keepProcessing    :=XML_TRUE;
 p.hasParamEntityRefs:=XML_FALSE;
 p.standalone        :=XML_FALSE;

 result:=p;

end;

{ dtdDestroy }
procedure dtdDestroy(p : DTD_ptr; isDocEntity : XML_Bool; ms : XML_Memory_Handling_Suite_ptr );
var
 iter : HASH_TABLE_ITER;

 e : ELEMENT_TYPE_ptr;

begin
 hashTableIterInit(@iter ,@p.elementTypes );

 repeat
  e:=ELEMENT_TYPE_ptr(hashTableIterNext(@iter ) );

  if e = NIL then
   break;

  if e.allocDefaultAtts <> 0 then
   ms.free_fcn(pointer(e.defaultAtts ) ,e.defaultAttsAlloc );

 until false;

 hashTableDestroy(@p.generalEntities );

{$IFDEF XML_DTD }
 hashTableDestroy(@p.paramEntities );

{$ENDIF }

 hashTableDestroy(@p.elementTypes );
 hashTableDestroy(@p.attributeIds );
 hashTableDestroy(@p.prefixes );

 poolDestroy(@p.pool );
 poolDestroy(@p.entityValuePool );

 if isDocEntity <> 0 then
  begin
   ms.free_fcn(pointer(p.scaffIndex ) ,p.scaffAlloc );
   ms.free_fcn(pointer(p.scaffold ) ,sizeof(CONTENT_SCAFFOLD ) );

  end;

 ms.free_fcn(pointer(p ) ,sizeof(DTD ) );

end;

{ handleUnknownEncoding ..}
function handleUnknownEncoding(parser : XML_Parser; encodingName : XML_Char_ptr ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ initializeEncoding }
function initializeEncoding(parser : XML_Parser ) : XML_Error;
var
 s  : char_ptr;
 ok : int;

begin
{$IFDEF XML_UNICODE ..}


{$ELSE }
 s:=pointer(parser.m_protocolEncodingName );

{$ENDIF }

 if parser.m_ns <> 0 then
  ok:=XmlInitEncodingNS(@parser.m_initEncoding ,@parser.m_encoding ,pointer(s ) )
 else
  ok:=XmlInitEncoding(@parser.m_initEncoding ,@parser.m_encoding ,pointer(s ) );

 if ok <> 0 then
  result:=XML_ERROR_NONE
 else
  result:=handleUnknownEncoding(parser ,parser.m_protocolEncodingName );

end;

{ reportDefault ..}
procedure reportDefault(parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr );
begin
end;

{ getContext ..}
function getContext(parser : XML_Parser ) : XML_Char_ptr;
begin
Result:=nil;
end;

{ processXmlDecl }
function processXmlDecl(parser : XML_Parser; isGeneralTextEntity : int; s ,next : char_ptr ) : XML_Error;
var
 encodingName ,version ,versionend : char_ptr;

 storedEncName ,storedversion : XML_Char_ptr;

 newEncoding : ENCODING_ptr;

 standalone ,ok : int;

 result_ : XML_Error;

begin
 encodingName :=NIL;
 storedEncName:=NIL;
 newEncoding  :=NIL;
 version      :=NIL;
 storedversion:=NIL;
 standalone   :=-1;

 if parser.m_ns <> 0 then
  ok:=
   XmlParseXmlDeclNS(
    isGeneralTextEntity ,parser.m_encoding ,pointer(s ) ,pointer(next ) ,
    @parser.m_eventPtr ,@version ,@versionend ,@encodingName ,
    @newEncoding ,@standalone )
 else
  ok:=
   XmlParseXmlDecl(
    isGeneralTextEntity ,parser.m_encoding ,pointer(s ) ,pointer(next ) ,
    @parser.m_eventPtr ,@version ,@versionend ,@encodingName ,
    @newEncoding ,@standalone );

 if ok = 0 then
  if isGeneralTextEntity <> 0 then
   begin
    result:=XML_ERROR_TEXT_DECL;

    exit;

   end
  else
   begin
    result:=XML_ERROR_XML_DECL;

    exit;

   end;

 if (isGeneralTextEntity = 0 ) and
    (standalone = 1 ) then
  begin
   parser.m_dtd.standalone:=XML_TRUE;

  {$IFDEF XML_DTD }
   if parser.m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE then
    parser.m_paramEntityParsing:=XML_PARAM_ENTITY_PARSING_NEVER;

  {$ENDIF }

  end;

 if @parser.m_xmlDeclHandler <> NIL then
  begin
   if encodingName <> NIL then
    begin
     storedEncName:=
      poolStoreString(
       @parser.m_temp2Pool ,
       parser.m_encoding ,
       encodingName,
       char_ptr(ptrcomp(encodingName ) + XmlNameLength(parser.m_encoding ,pointer(encodingName ) ) ) );

     if storedEncName = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     poolFinish(@parser.m_temp2Pool );

    end;

   if version <> NIL then
    begin
     storedversion:=
      poolStoreString(
       @parser.m_temp2Pool ,
       parser.m_encoding ,
       version ,
       char_ptr(ptrcomp(versionend ) - parser.m_encoding.minBytesPerChar ) );

     if storedversion = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

    end;

   parser.m_xmlDeclHandler(
    parser.m_handlerArg ,storedversion ,storedEncName ,standalone );

  end
 else
  if @parser.m_defaultHandler <> NIL then
   reportDefault(parser ,parser.m_encoding ,s ,next );

 if parser.m_protocolEncodingName = NIL then
  begin
   if newEncoding <> NIL then
    begin
     if newEncoding.minBytesPerChar <> parser.m_encoding.minBytesPerChar then
      begin
       parser.m_eventPtr:=encodingName;

       result:=XML_ERROR_INCORRECT_ENCODING;

       exit;

      end;

     parser.m_encoding:=newEncoding;

    end
   else
    if encodingName <> NIL then
     begin
      if storedEncName = NIL then
       begin
        storedEncName:=
         poolStoreString(
          @parser.m_temp2Pool ,parser.m_encoding ,encodingName ,
          char_ptr(ptrcomp(encodingName ) + XmlNameLength(parser.m_encoding ,pointer(encodingName ) ) ) );

        if storedEncName = NIL then
         begin
          result:=XML_ERROR_NO_MEMORY;

          exit;

         end;

       end;

      result_:=handleUnknownEncoding(parser ,storedEncName );

      poolClear(@parser.m_temp2Pool );

      if result_ = XML_ERROR_UNKNOWN_ENCODING then
       parser.m_eventPtr:=encodingName;

      result:=result_;

      exit;

     end;

  end;

 if (storedEncName <> NIL ) or
    (storedversion <> NIL ) then
   poolClear(@parser.m_temp2Pool );

 result:=XML_ERROR_NONE;

end;

{ poolClear }
procedure poolClear(pool : STRING_POOL_ptr );
var
 p ,tem : BLOCK_ptr;

begin
 if pool.freeBlocks = NIL then
  pool.freeBlocks:=pool.blocks

 else
  begin
   p:=pool.blocks;

   while p <> NIL do
    begin
     tem            :=p.next;
     p.next         :=pool.freeBlocks;
     pool.freeBlocks:=p;
     p              :=tem;

    end;

  end;

 pool.blocks:=NIL;
 pool.start :=NIL;
 pool.ptr   :=NIL;
 pool.end_  :=NIL;

end;

{ poolDestroy }
procedure poolDestroy(pool : STRING_POOL_ptr );
var
 p ,tem : BLOCK_ptr;

begin
 p:=pool.blocks;

 while p <> NIL do
  begin
   tem:=p.next;

   pool.mem.free_fcn(pointer(p ) ,p.alloc );

   p:=tem;

  end;

 p:=pool.freeBlocks;

 while p <> NIL do
  begin
   tem:=p.next;

   pool.mem.free_fcn(pointer(p ) ,p.alloc );

   p:=tem;

  end;

end;

{ poolGrow }
function poolGrow(pool : STRING_POOL_ptr ) : XML_Bool;
var
 tem : BLOCK_ptr;

 blockSize : int;

begin
 if pool.freeBlocks <> NIL then
  begin
   if pool.start = NIL then
    begin
     pool.blocks     :=pool.freeBlocks;
     pool.freeBlocks :=pool.freeBlocks.next;
     pool.blocks.next:=NIL;

     pool.start:=@pool.blocks.s;
     pool.end_ :=XML_Char_ptr(ptrcomp(pool.start ) + pool.blocks.size * sizeof(XML_Char ) );
     pool.ptr  :=pool.start;

     result:=XML_TRUE;

     exit;

    end;

   if ptrcomp(pool.end_ ) - ptrcomp(pool.start ) < pool.freeBlocks.size then
    begin
     tem:=pool.freeBlocks.next;

     pool.freeBlocks.next:=pool.blocks;
     pool.blocks         :=pool.freeBlocks;
     pool.freeBlocks     :=tem;

     move(
      pool.start^ ,
      pointer(@pool.blocks.s )^ ,
      ptrcomp(pool.end_ ) - ptrcomp(pool.start ) );

     pool.ptr  :=XML_Char_ptr(ptrcomp(@pool.blocks.s ) + ptrcomp(pool.ptr ) - ptrcomp(pool.start ) );
     pool.start:=@pool.blocks.s;
     pool.end_ :=XML_Char_ptr(ptrcomp(pool.start ) + pool.blocks.size * sizeof(XML_Char ) );

     result:=XML_TRUE;

     exit;

    end;

  end;

 if (pool.blocks <> NIL ) and
    (pool.start = @pool.blocks.s ) then
  begin
   blockSize:=(ptrcomp(pool.end_ ) - ptrcomp(pool.start ) ) * 2 div sizeof(XML_Char );

   pool.mem.realloc_fcn(
    pointer(pool.blocks ) ,
    pool.blocks.alloc ,
    (sizeof(BLOCK_ptr ) + sizeof(int ) * 2 ) + blockSize * sizeof(XML_Char ) );

   if pool.blocks = NIL then
    begin
     result:=XML_FALSE;

     exit;

    end
   else
    pool.blocks.alloc:=(sizeof(BLOCK_ptr ) + sizeof(int ) * 2 ) + blockSize * sizeof(XML_Char );

   pool.blocks.size:=blockSize;

   pool.ptr  :=XML_Char_ptr(ptrcomp(@pool.blocks.s ) + (ptrcomp(pool.ptr ) - ptrcomp(pool.start ) ) );
   pool.start:=@pool.blocks.s;
   pool.end_ :=XML_Char_ptr(ptrcomp(pool.start ) + blockSize * sizeof(XML_Char ) );

  end
 else
  begin
   blockSize:=(ptrcomp(pool.end_ ) - ptrcomp(pool.start ) ) div sizeof(XML_Char );

   if blockSize < INIT_BLOCK_SIZE then
    blockSize:=INIT_BLOCK_SIZE
   else
    blockSize:=blockSize * 2;

   pool.mem.malloc_fcn(
    pointer(tem ) ,
    (sizeof(BLOCK_ptr ) + sizeof(int ) * 2 ) + blockSize * sizeof(XML_Char ) );

   if tem = NIL then
    begin
     result:=XML_FALSE;

     exit;

    end;

   tem.size :=blockSize;
   tem.alloc:=(sizeof(BLOCK_ptr ) + sizeof(int ) * 2 ) + blockSize * sizeof(XML_Char );
   tem.next :=pool.blocks;

   pool.blocks:=tem;

   if pool.ptr <> pool.start then
    move(
     pool.start^ ,
     pointer(@tem.s )^ ,
     ptrcomp(pool.ptr ) - ptrcomp(pool.start ) );

   pool.ptr  :=XML_Char_ptr(ptrcomp(@tem.s ) + (ptrcomp(pool.ptr ) - ptrcomp(pool.start ) ) * sizeof(XML_Char ) );
   pool.start:=@tem.s;
   pool.end_ :=XML_Char_ptr(ptrcomp(@tem.s ) + blockSize * sizeof(XML_Char ) );

  end;

 result:=XML_TRUE;

end;

{ poolAppend }
function poolAppend(pool : STRING_POOL_ptr; enc : ENCODING_ptr; ptr ,end_ : char_ptr ) : XML_Char_ptr;
begin
 if (pool.ptr = NIL ) and
    (poolGrow(pool ) = 0 ) then
  begin
   result:=NIL;

   exit;

  end;

 repeat
  XmlConvert(
   enc ,@ptr ,end_ ,
   ICHAR_ptr_ptr(@pool.ptr ) ,
   ICHAR_ptr(pool.end_ ) );

  if ptr = end_ then
   break;

  if poolGrow(pool ) = 0 then
   result:=NIL;

 until false;

 result:=pool.start;

end;

{ poolStoreString }
function poolStoreString(pool : STRING_POOL_ptr; enc : ENCODING_ptr; ptr ,end_ : char_ptr ) : XML_Char_ptr;
begin
 if poolAppend(pool ,enc ,ptr ,end_ ) = NIL then
  begin
   result:=NIL;

   exit;

  end;

 if (pool.ptr = pool.end_ ) and
    (poolGrow(pool ) = 0 ) then
  begin
   result:=NIL;

   exit;

  end;

 pool.ptr^:=XML_Char(0 );

 inc(ptrcomp(pool.ptr ) );

 result:=pool.start;

end;

{ poolCopyString }
function poolCopyString(pool : STRING_POOL_ptr; s : XML_Char_ptr ) : XML_Char_ptr;
begin
 repeat
   if (poolAppendChar(pool, s^)=0) then
     exit(nil);
   inc(ptrcomp(s ) ,sizeof(XML_Char ) );
 until s^ = XML_Char(0 );
 s := pool.start;
 poolFinish(pool);
 result:=s;
end;

{ poolAppendString {..}
function poolAppendString(pool : STRING_POOL_ptr; s : XML_Char_ptr ) : XML_Char_ptr;
begin
 Result:=nil;
end;

{ poolStart }
function poolStart(pool : STRING_POOL_ptr ) : XML_Char_ptr;
begin
 result:=pool.start;

end;

{ poolLength }
function poolLength(pool : STRING_POOL_ptr ) : int;
begin
 result:=ptrcomp(pool.ptr ) - ptrcomp(pool.start );

end;

{ poolChop }
procedure poolChop(pool : STRING_POOL_ptr );
begin
 dec(ptrcomp(pool.ptr ) ,sizeof(XML_Char ) );

end;

{ poolLastChar }
function poolLastChar(pool : STRING_POOL_ptr ) : XML_Char;
begin
 result:=XML_Char_ptr(ptrcomp(pool.ptr ) - 1 * sizeof(XML_Char ) )^;

end;

{ poolDiscard }
procedure poolDiscard(pool : STRING_POOL_ptr );
begin
 pool.ptr:=pool.start;

end;

{ poolFinish }
procedure poolFinish(pool : STRING_POOL_ptr );
begin
 pool.start:=pool.ptr;

end;

{ poolAppendChar }
function poolAppendChar(pool : STRING_POOL_ptr; c : char ) : int;
begin
 if (pool.ptr = pool.end_ ) and
    (poolGrow(pool ) = 0 ) then
  result:=0
 else
  begin
   pool.ptr^:=c;

   inc(ptrcomp(pool.ptr ) );

   result:=1;

  end;

end;

{ keyeq }
function keyeq(s1 ,s2 : KEY ) : XML_Bool;
begin
 while s1^ = s2^ do
  begin
   if s1^ = #0 then
    begin
     result:=XML_TRUE;

     exit;

    end;

   inc(ptrcomp(s1 ) ,sizeof(XML_Char ) );
   inc(ptrcomp(s2 ) ,sizeof(XML_Char ) );

  end;

 result:=XML_FALSE;

end;

{ hash }
function hash(s : KEY ) : int32u;
var
 h : int32u;

begin
 h:=0;

 while s^ <> XML_Char(0 ) do
  begin
   h:=CHAR_HASH(h ,s^ );

   inc(ptrcomp(s ) ,sizeof(XML_Char ) );

  end;

 result:=h;

end;

{ lookup }
function lookup(table : HASH_TABLE_ptr; name : KEY; createSize : size_t ) : NAMED_ptr;
var
 i ,tsize ,newSize ,j : size_t;

 h ,mask ,newMask ,newHash : int32u;

 step ,newPower : int8u;

 newV : NAMED_ptr_ptr;

begin
 newV:=nil;
 if table.size = 0 then
  begin
   if createSize = 0 then
    begin
     result:=NIL;

     exit;

    end;

   table.power:=INIT_POWER;

  { table->size is a power of 2 }
   table.size:=size_t(1 shl INIT_POWER );

   tsize:=table.size * sizeof(NAMED_ptr );

   table.mem.malloc_fcn(pointer(table.v ) ,tsize );

   if table.v = NIL then
    begin
     table.size:=0;

     result:=NIL;

     exit;

    end
   else
    table.a:=tsize;

   fillchar(table.v^ ,tsize ,0 );

   i:=hash(name ) and (table.size - 1 );

  end
 else
  begin
   h   :=hash(name );
   mask:=table.size - 1;
   step:=0;
   i   :=h and mask;

   while NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^ <> NIL do
    begin
     if keyeq(
         name ,
         NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^^.name ) <> 0 then
      begin
       result:=NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^;

       exit;

      end;

     if step = 0 then
      step:=PROBE_STEP(h ,mask ,table.power );

     if i < step then
      inc(i ,table.size - step )
     else
      dec(i ,step );

    end;

   if createSize = 0 then
    begin
     result:=NIL;

     exit;

    end;

  { check for overflow (table is half full) }
   if table.used shr (table.power - 1 ) <> 0 then
    begin
     newPower:=table.power + 1;
     newSize :=size_t(1 shl newPower );
     newMask :=newSize - 1;
     tsize   :=newSize * sizeof(NAMED_ptr );

     table.mem.malloc_fcn(pointer(newV ) ,tsize );

     if newV = NIL then
      begin
       result:=NIL;

       exit;

      end;

     fillchar(newV^ ,tsize ,0 );

     i:=0;

     while i < table.size do
      begin
       if NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^ <> NIL then
        begin
         newHash:=hash(NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^^.name );
         j      :=newHash and newMask;
         step   :=0;

         while NAMED_ptr_ptr(ptrcomp(newV ) + j * sizeof(NAMED_ptr ) )^ <> NIL do
          begin
           if step = 0 then
            step:=PROBE_STEP(newHash ,newMask ,newPower );

           if j < step then
            inc(j ,newSize - step )
           else
            dec(j ,step );

          end;

         NAMED_ptr_ptr(ptrcomp(newV ) + j * sizeof(NAMED_ptr ) )^:=
          NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^;

        end;

       inc(i );

      end;

     table.mem.free_fcn(pointer(table.v ) ,table.a );

     table.v    :=newV;
     table.a    :=tsize;
     table.power:=newPower;
     table.size :=newSize;

     i   :=h and newMask;
     step:=0;

     while NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^ <> NIL do
      begin
       if step = 0 then
        step:=PROBE_STEP(h ,newMask ,newPower );

       if i < step then
        inc(i ,newSize - step )
       else
        dec(i ,step );

      end;

    end;

  end;

 table.mem.malloc_fcn(
  pointer(NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^ ) ,
  createSize );

 if NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^ = NIL then
  begin
   result:=NIL;

   exit;

  end;

 fillchar(NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^^ ,createSize ,0 );

 NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^^.name :=name;
 NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^^.alloc:=createSize;

 inc(table.used );

 result:=NAMED_ptr_ptr(ptrcomp(table.v ) + i * sizeof(NAMED_ptr ) )^;

end;

{ normalizePublicId }
procedure normalizePublicId(publicId : XML_Char_ptr );
var
 p ,s : XML_Char_ptr;

begin
 p:=publicId;
 s:=publicId;

 while s^ <> XML_Char(0 ) do
  begin
   case s^ of
    XML_Char($20 ) ,XML_Char($D ) ,XML_Char($A ) :
     if (p <> publicId ) and
        (XML_Char_ptr(ptrcomp(p ) -1 * sizeof(XML_Char ) )^ <> XML_Char($20 ) ) then
      begin
       p^:=XML_Char($20 );

       inc(ptrcomp(p ) ,sizeof(XML_Char ) );

      end;

    else
     begin
      p^:=s^;

      inc(ptrcomp(p ) ,sizeof(XML_Char ) );

     end;

   end;

   inc(ptrcomp(s ) ,sizeof(XML_Char ) );

  end;

 if (p <> publicId ) and
    (XML_Char_ptr(ptrcomp(p ) -1 * sizeof(XML_Char ) )^ = XML_Char($20 ) ) then
  dec(ptrcomp(p ) ,sizeof(XML_Char ) );

 p^:=XML_T(#0 );

end;

{ setElementTypePrefix {..}
function setElementTypePrefix(parser : XML_Parser; elementType : ELEMENT_TYPE_ptr ) : int;
begin
 Result:=0;
end;

{ addBinding {..}
{ addBinding overwrites the value of prefix.binding without checking.
  Therefore one must keep track of the old value outside of addBinding. }
function addBinding(
          parser : XML_Parser; prefix : PREFIX_ptr; attId : ATTRIBUTE_ID_ptr;
          uri : XML_Char_ptr; bindingsPtr : BINDING_ptr_ptr ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ storeRawNames }
{ Initially tag.rawName always points into the parse buffer;
  for those TAG instances opened while the current parse buffer was
  processed, and not yet closed, we need to store tag.rawName in a more
  permanent location, since the parse buffer is about to be discarded. }
function storeRawNames(parser : XML_Parser ) : XML_Bool;
var
 tag : TAG_ptr;

 bufSize ,nameLen : int;

 rawNameBuf ,temp : char_ptr;

begin
 tag:=parser.m_tagStack;

 while tag <> NIL do
  begin
   nameLen   :=sizeof(XML_Char ) * (tag.name.strLen + 1 );
   rawNameBuf:=char_ptr(ptrcomp(tag.buf ) + nameLen );

  { Stop if already stored. Since tagStack is a stack, we can stop
    at the first entry that has already been copied; everything
    below it in the stack is already been accounted for in a
    previous call to this function. }
   if tag.rawName = rawNameBuf then
    break;

  { For re-use purposes we need to ensure that the
    size of tag.buf is a multiple of sizeof(XML_Char ). }
   bufSize:=nameLen + ROUND_UP(tag.rawNameLength ,sizeof(XML_Char ) );

   if bufSize > ptrcomp(tag.bufEnd ) - ptrcomp(tag.buf ) then
    begin
     if parser.m_mem.realloc_fcn(pointer(tag.buf ) ,tag.alloc ,bufSize ) then
      temp:=tag.buf
     else
      temp:=NIL;

     if temp = NIL then
      begin
       result:=XML_FALSE;

       exit;

      end;

     tag.alloc:=bufSize; 

    { if tag.name.str points to tag.buf (only when namespace
      processing is off) then we have to update it }
     if tag.name.str = XML_Char_ptr(tag.buf ) then
      tag.name.str:=XML_Char_ptr(temp );

    { if tag->name.localPart is set (when namespace processing is on)
      then update it as well, since it will always point into tag->buf }
     if tag.name.localPart <> NIL then
      tag.name.localPart:=
       XML_Char_ptr(
        ptrcomp(temp ) +
        (ptrcomp(tag.name.localPart ) - ptrcomp(tag.buf ) ) );

     tag.buf   :=temp;
     tag.bufEnd:=char_ptr(ptrcomp(temp ) + bufSize );
     rawNameBuf:=char_ptr(ptrcomp(temp ) + nameLen );

    end;

   move(tag.rawName^ ,rawNameBuf^ ,tag.rawNameLength );

   tag.rawName:=rawNameBuf;
   tag        :=tag.parent;

  end;

 result:=XML_TRUE;

end;

{ storeAtts }
{ Precondition: all arguments must be non-NULL;
  Purpose:
  - normalize attributes
  - check attributes for well-formedness
  - generate namespace aware attribute names (URI, prefix)
  - build list of attributes for startElementHandler
  - default attributes
  - process namespace declarations (check and report them)
  - generate namespace aware element name (URI, prefix) }
function storeAtts(
          parser : XML_Parser; enc : ENCODING_ptr;
          attStr : char_ptr; tagNamePtr : TAG_NAME_ptr;
          bindingsPtr : BINDING_ptr_ptr ) : XML_Error;
var
 dtd : DTD_ptr;

 elementType : ELEMENT_TYPE_ptr;

 nDefaultAtts ,attIndex ,prefixLen ,i ,n ,nPrefixes ,oldAttsSize ,j ,nsAttsSize : int;

 version ,uriHash ,mask : int32u;

 step : int8u;

 appAtts : XML_Char_ptr_ptr; { the attribute list for the application }

 uri ,localPart ,name ,s ,s1 ,s2 : XML_Char_ptr;

 c : XML_Char;

 binding ,b : BINDING_ptr;

 attId ,id : ATTRIBUTE_ID_ptr;

 result_ : XML_Error;

 isCdata : XML_Bool;

 da : DEFAULT_ATTRIBUTE_ptr;

 p : TAG_ptr;
begin
 uri:=nil;
 dtd:=parser.m_dtd; { save one level of indirection }

 attIndex :=0;
 nPrefixes:=0;

{ lookup the element type name }
 elementType:=
  ELEMENT_TYPE_ptr(lookup(
   @dtd.elementTypes ,tagNamePtr.str ,0 ) );

 if elementType = NIL then
  begin
   name:=poolCopyString(@dtd.pool ,tagNamePtr.str );

   if name = NIL then
    begin
     result:=XML_ERROR_NO_MEMORY;

     exit;

    end;

   elementType:=
    ELEMENT_TYPE_ptr(lookup(
     @dtd.elementTypes ,name ,sizeof(ELEMENT_TYPE ) ) );

   if elementType = NIL then
    begin
     result:=XML_ERROR_NO_MEMORY;

     exit;

    end;

   if (parser.m_ns <> 0 ) and
      (setElementTypePrefix(parser ,elementType ) = 0 ) then
    begin
     result:=XML_ERROR_NO_MEMORY;

     exit;

    end;

  end;

 nDefaultAtts:=elementType.nDefaultAtts;

{ get the attributes from the tokenizer }
 n:=XmlGetAttributes(enc ,pointer(attStr ) ,parser.m_attsSize ,parser.m_atts );

 if n + nDefaultAtts > parser.m_attsSize then
  begin
   oldAttsSize      :=parser.m_attsSize;
   parser.m_attsSize:=n + nDefaultAtts + INIT_ATTS_SIZE;

   if not parser.m_mem.realloc_fcn(
           pointer(parser.m_atts ) ,
           parser.m_attsAlloc ,
           parser.m_attsSize * sizeof(ATTRIBUTE ) ) then
    begin
     result:=XML_ERROR_NO_MEMORY;

     exit;

    end
   else
    parser.m_attsAlloc:=parser.m_attsSize * sizeof(ATTRIBUTE );

   if n > oldAttsSize then
    XmlGetAttributes(enc ,pointer(attStr ) ,n ,parser.m_atts );

  end;

 appAtts:=XML_Char_ptr_ptr(parser.m_atts );

 i:=0;

 while i < n do
  begin
  { add the name and value to the attribute list }
   attId:=
    getAttributeId(
     parser ,enc ,
     pointer(ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.name ) ,
     pointer(
      ptrcomp(ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.name ) +
      XmlNameLength(enc ,ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.name ) ) );

   if attId = NIL then
    begin
     result:=XML_ERROR_NO_MEMORY;

     exit;

    end;

  { Detect duplicate attributes by their QNames. This does not work when
    namespace processing is turned on and different prefixes for the same
    namespace are used. For this case we have a check further down. }
   if XML_Char_ptr(ptrcomp(attId.name ) - 1 * sizeof(XML_Char ) )^ <> XML_Char(0 ) then
    begin
     if enc = parser.m_encoding then
      parser.m_eventPtr:=pointer(ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.name );

     result:=XML_ERROR_DUPLICATE_ATTRIBUTE;

     exit;

    end;

   XML_Char_ptr(ptrcomp(attId.name ) - 1 * sizeof(XML_Char ) )^:=XML_Char(1 );

   XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=attId.name;

   inc(attIndex );

   if ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.normalized = #0 then
    begin
     isCdata:=XML_TRUE;

    { figure out whether declared as other than CDATA }
     if attId.maybeTokenized <> 0 then
      begin
       j:=0;

       while j < nDefaultAtts do
        begin
         if attId = DEFAULT_ATTRIBUTE_ptr(ptrcomp(elementType.defaultAtts ) + j * sizeof(DEFAULT_ATTRIBUTE ) )^.id then
          begin
           isCdata:=DEFAULT_ATTRIBUTE_ptr(ptrcomp(elementType.defaultAtts ) + j * sizeof(DEFAULT_ATTRIBUTE ) )^.isCdata;

           break;

          end;

         inc(j );

        end;

      end;

    { normalize the attribute value }
     result_:=
      storeAttributeValue(
       parser ,enc ,isCdata ,
       pointer(ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.valuePtr ) ,
       pointer(ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.valueEnd ) ,
       @parser.m_tempPool );

     if result_ <> XML_Error(0 ) then
      begin
       result:=result_;

       exit;

      end;

     XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=poolStart(@parser.m_tempPool );

     poolFinish(@parser.m_tempPool );

    end
   else
    begin
    { the value did not need normalizing }
     XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=
      poolStoreString(
       @parser.m_tempPool ,enc ,
       pointer(ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.valuePtr ) ,
       pointer(ATTRIBUTE_ptr(ptrcomp(parser.m_atts ) + i * sizeof(ATTRIBUTE ) )^.valueEnd ) );

     if XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^ = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     poolFinish(@parser.m_tempPool );

    end;

  { handle prefixed attribute names }
   if attId.prefix <> NIL then
    if attId.xmlns <> 0 then
     begin
     { deal with namespace declarations here }
      result_:=
       addBinding(
        parser ,attId.prefix ,attId ,
        XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^ ,
        bindingsPtr );

      if result_ <> XML_Error(0 ) then
       begin
        result:=result_;

        exit;

       end;

      dec(attIndex );

     end
    else
     begin
     { deal with other prefixed names later }
      inc(attIndex );
      inc(nPrefixes );

      XML_Char_ptr(ptrcomp(attId.name ) - 1 * sizeof(XML_Char ) )^:=XML_Char(2 );

     end
   else
    inc(attIndex );

   inc(i );

  end;

{ set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex }
 parser.m_nSpecifiedAtts:=attIndex;

 if (elementType.idAtt <> NIL ) and
    (XML_Char_ptr(ptrcomp(elementType.idAtt.name ) - 1 * sizeof(XML_Char ) )^ <> XML_Char(0 ) ) then
  begin
   i:=0;

   while i < attIndex do
    begin
     if XML_Char_ptr_ptr(ptrcomp(appAtts ) + i * sizeof(XML_Char_ptr ) )^ = elementType.idAtt.name then
      begin
       parser.m_idAttIndex:=i;

       break;

      end;

     inc(i ,2 );

    end;

  end
 else
  parser.m_idAttIndex:=-1;

{ do attribute defaulting }
 i:=0;

 while i < nDefaultAtts do
  begin
   da:=DEFAULT_ATTRIBUTE_ptr(ptrcomp(elementType.defaultAtts ) + i * sizeof(DEFAULT_ATTRIBUTE ) );

   if (XML_Char_ptr(ptrcomp(da.id.name ) - 1 * sizeof(XML_Char ) )^ = XML_Char(0 ) ) and
      (da.value <> NIL ) then
    if da.id.prefix <> NIL then
     if da.id.xmlns <> 0 then
      begin
       result_:=
        addBinding(
         parser ,da.id.prefix ,da.id ,
         da.value ,bindingsPtr );

       if result_ <> XML_Error(0 ) then
        begin
         result:=result_;

         exit;

        end;

      end
     else
      begin
       XML_Char_ptr(ptrcomp(da.id.name ) - 1 * sizeof(XML_Char ) )^:=XML_Char(2 );

       inc(nPrefixes );

       XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=da.id.name;

       inc(attIndex );

       XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=da.value;

       inc(attIndex );

      end
    else
     begin
      XML_Char_ptr(ptrcomp(da.id.name ) - 1 * sizeof(XML_Char ) )^:=XML_Char(1 );

      XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=da.id.name;

      inc(attIndex );

      XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=da.value;

      inc(attIndex );

     end;

   inc(i );

  end;

 XML_Char_ptr_ptr(ptrcomp(appAtts ) + attIndex * sizeof(XML_Char_ptr ) )^:=NIL;

{ expand prefixed attribute names, check for duplicates,
  and clear flags that say whether attributes were specified }
 i:=0;

 if nPrefixes <> 0 then
  begin
  { j = hash table index }
   version   :=parser.m_nsAttsVersion;
   nsAttsSize:=1 shl parser.m_nsAttsPower;

  { size of hash table must be at least 2 * (# of prefixed attributes) }
   if shr_int32(nPrefixes shl 1 ,parser.m_nsAttsPower ) <> 0 then{ true for nsAttsPower = 0 }
    begin
    { hash table size must also be a power of 2 and >= 8 }
     while shr_int32(nPrefixes ,parser.m_nsAttsPower ) <> 0 do
      inc(parser.m_nsAttsPower );

     if parser.m_nsAttsPower < 3 then
      parser.m_nsAttsPower:=3;

     nsAttsSize:=1 shl parser.m_nsAttsPower;

     if not parser.m_mem.realloc_fcn(
         pointer(parser.m_nsAtts ) ,
         parser.m_nsAttsAlloc ,
         nsAttsSize * sizeof(NS_ATT ) ) then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end
     else
      parser.m_nsAttsAlloc:=nsAttsSize * sizeof(NS_ATT );

     version:=0;  { force re-initialization of nsAtts hash table }

    end;

  { using a version flag saves us from initializing nsAtts every time }
   if version = 0 then { initialize version flags when version wraps around }
    begin
     version:=INIT_ATTS_VERSION;

     j:=nsAttsSize;

     while j <> 0 do
      begin
       dec(j );

       NS_ATT_ptr(ptrcomp(parser.m_nsAtts ) + j * sizeof(NS_ATT ) )^.version:=version;

      end;

    end;

   dec(version );

   parser.m_nsAttsVersion:=version;

  { expand prefixed names and check for duplicates }
   while i < attIndex do
    begin
     s:=XML_Char_ptr_ptr(ptrcomp(appAtts ) + i * sizeof(XML_Char_ptr ) )^;

     if XML_Char_ptr(ptrcomp(s ) - 1 * sizeof(XML_Char ) )^ = XML_Char(2 ) then { prefixed }
      begin
       uriHash:=0;

       XML_Char_ptr(ptrcomp(s ) - 1 * sizeof(XML_Char ) )^:=XML_Char(0 ); { clear flag }

       id:=ATTRIBUTE_ID_ptr(lookup(@dtd.attributeIds ,s ,0 ) );
       b :=id.prefix.binding;

       if b = NIL then
        begin
         result:=XML_ERROR_UNBOUND_PREFIX;

         exit;

        end;

      { as we expand the name we also calculate its hash value }
       j:=0;

       while j < b.uriLen do
        begin
         c:=XML_Char_ptr(ptrcomp(b.uri ) + j * sizeof(XML_Char ) )^;

         if poolAppendChar(@parser.m_tempPool ,c ) = 0 then
          begin
           result:=XML_ERROR_NO_MEMORY;

           exit;

          end;

         uriHash:=CHAR_HASH(uriHash ,c );

         inc(j );

        end;

       while s^ <> XML_T(':' ) do
        inc(ptrcomp(s ) ,sizeof(XML_Char ) );

       repeat
         c:=s^;
         if poolAppendChar(@parser.m_tempPool ,s^ ) = 0 then
         begin
           result:=XML_ERROR_NO_MEMORY;
           exit;
         end;
         uriHash:=CHAR_HASH(uriHash ,c );
         inc(ptrcomp(s ) ,sizeof(XML_Char ) );
       until s^ = XML_Char(0 );

      { Check hash table for duplicate of expanded name (uriName).
        Derived from code in lookup(HASH_TABLE *table, ...). }
       step:=0;
       mask:=nsAttsSize - 1;
       j   :=uriHash and mask;  { index into hash table }

       while NS_ATT_ptr(ptrcomp(parser.m_nsAtts ) + j * sizeof(NS_ATT ) )^.version = version do
        begin
        { for speed we compare stored hash values first }
         if uriHash = NS_ATT_ptr(ptrcomp(parser.m_nsAtts ) + j * sizeof(NS_ATT ) )^.hash then
          begin
           s1:=poolStart(@parser.m_tempPool );
           s2:=NS_ATT_ptr(ptrcomp(parser.m_nsAtts ) + j * sizeof(NS_ATT ) )^.uriName;

          { s1 is null terminated, but not s2 }
           while (s1^ = s2^ ) and
                 (s1^ <> XML_Char(0 ) ) do
            begin
             inc(ptrcomp(s1 ) ,sizeof(XML_Char ) );
             inc(ptrcomp(s2 ) ,sizeof(XML_Char ) );

            end;

           if s1^ = XML_Char(0 ) then
            begin
             result:=XML_ERROR_DUPLICATE_ATTRIBUTE;

             exit;

            end;

          end;

         if step = 0 then
          step:=PROBE_STEP(uriHash ,mask ,parser.m_nsAttsPower );

         if j < step then
          inc(j  ,nsAttsSize - step )
         else
          dec(j ,step );

        end;

       if parser.m_ns_triplets <> 0 then { append namespace separator and prefix }
        begin
          XML_Char_ptr(ptrcomp(parser.m_tempPool.ptr ) - 1 * sizeof(XML_Char ) )^:=parser.m_namespaceSeparator;

          s:=b.prefix.name;

          repeat
            if poolAppendChar(@parser.m_tempPool ,s^ ) = 0 then
            begin
             result:=XML_ERROR_NO_MEMORY;
             exit;
            end;
            inc(ptrcomp(s ) ,sizeof(XML_Char ) );
          until s^ = XML_Char(0 );
        end;

      { store expanded name in attribute list }
       s:=poolStart(@parser.m_tempPool );

       poolFinish(@parser.m_tempPool );

       XML_Char_ptr_ptr(ptrcomp(appAtts ) + i * sizeof(XML_Char_ptr ) )^:=s;

      { fill empty slot with new version, uriName and hash value }
       NS_ATT_ptr(ptrcomp(parser.m_nsAtts ) + j * sizeof(NS_ATT ) )^.version:=version;
       NS_ATT_ptr(ptrcomp(parser.m_nsAtts ) + j * sizeof(NS_ATT ) )^.hash   :=uriHash;
       NS_ATT_ptr(ptrcomp(parser.m_nsAtts ) + j * sizeof(NS_ATT ) )^.uriName:=s;

       dec(nPrefixes );

       if nPrefixes = 0 then
        begin
         inc(i ,2 );

         break;

        end;

      end
     else { not prefixed }
      XML_Char_ptr(ptrcomp(s ) - 1 * sizeof(XML_Char ) )^:=XML_Char(0 );  { clear flag }

     inc(i ,2 );

    end;

  end;

{ clear flags for the remaining attributes }
 while i < attIndex do
  begin
   XML_Char_ptr(
    ptrcomp(
     XML_Char_ptr_ptr(ptrcomp(appAtts ) + i * sizeof(XML_Char_ptr ) )^ )
     - 1 * sizeof(XML_Char ) )^:=XML_Char(0 );

   inc(i ,2 );

  end;

 binding:=bindingsPtr^;

 while binding <> NIL do
  begin
   XML_Char_ptr(ptrcomp(binding.attId.name ) - 1 * sizeof(XML_Char ) )^:=XML_Char(0 );

   binding:=binding.nextTagBinding;

  end;

 if parser.m_ns = 0 then
  begin
   result:=XML_ERROR_NONE;

   exit;

  end;

{ expand the element type name }
 if elementType.prefix <> NIL then
  begin
   binding:=elementType.prefix.binding;

   if binding = NIL then
    begin
     result:=XML_ERROR_UNBOUND_PREFIX;

     exit;

    end;

   localPart:=tagNamePtr.str;

   while localPart^ <> XML_T(':' ) do
    inc(ptrcomp(localPart ) ,sizeof(XML_Char ) );

  end
 else
  if dtd.defaultPrefix.binding <> NIL then
   begin
    binding  :=dtd.defaultPrefix.binding;
    localPart:=tagNamePtr.str;

   end
  else
   begin
    result:=XML_ERROR_NONE;

    exit;

   end;

 prefixLen:=0;

 if (parser.m_ns_triplets <> 0 ) and
    (binding.prefix.name <> NIL ) then
  begin
   while XML_Char_ptr(ptrcomp(binding.prefix.name ) + prefixLen * sizeof(XML_Char ) )^ <> XML_Char(0 ) do
    inc(prefixLen );

   inc(prefixLen ); { prefixLen includes null terminator }

  end;

 tagNamePtr.localPart:=localPart;
 tagNamePtr.uriLen   :=binding.uriLen;
 tagNamePtr.prefix   :=binding.prefix.name;
 tagNamePtr.prefixLen:=prefixLen;

 i:=0;

 while XML_Char_ptr(ptrcomp(localPart ) + i * sizeof(XML_Char ) )^ <> XML_Char(0 ) do
  inc(i );

 inc(i ); { i includes null terminator }

 n:=i + binding.uriLen + prefixLen;

 if n > binding.uriAlloc then
  begin
   parser.m_mem.malloc_fcn(pointer(uri ) ,(n + EXPAND_SPARE ) * sizeof(XML_Char ) );

   if uri = NIL then
    begin
     result:=XML_ERROR_NO_MEMORY;

     exit;

    end;

   j:=binding.uriAlloc;

   binding.uriAlloc:=n + EXPAND_SPARE;

   move(
    binding.uri^ ,
    uri^ ,
    binding.uriLen * sizeof(XML_Char ) );

   p:=parser.m_tagStack;

   while p <> NIL do
    begin
     if p.name.str = binding.uri then
      p.name.str:=uri;

     p:=p.parent;

    end;

   parser.m_mem.free_fcn(pointer(binding.uri ) ,j * sizeof(XML_Char ) );

   binding.uri:=uri;

  end;

{ if namespaceSeparator != '\0' then uri includes it already }
 uri:=XML_Char_ptr(ptrcomp(binding.uri ) + binding.uriLen * sizeof(XML_Char ) );

 move(
  localPart^ ,
  uri^ ,
  i * sizeof(XML_Char ) );

{ we always have a namespace separator between localPart and prefix }
 if prefixLen <> 0 then
  begin
   inc(ptrcomp(uri ) ,(i - 1 ) * sizeof(XML_Char ) );

   uri^:=parser.m_namespaceSeparator; { replace null terminator }

   move(
    binding.prefix.name^ ,
    XML_Char_ptr(ptrcomp(uri ) + 1 * sizeof(XML_Char ) )^ ,
    prefixLen * sizeof(XML_Char ) );

  end;

 tagNamePtr.str:=binding.uri;

 result:=XML_ERROR_NONE;

end;

{ processInternalEntity {..}
function processInternalEntity(parser : XML_Parser; entity : ENTITY_ptr; betweenDecl : XML_Bool ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ epilogProcessor }
function epilogProcessor(parser : XML_Parser; s ,end_ : char_ptr; nextPtr : char_ptr_ptr ) : XML_Error;
var
 next : char_ptr;

 tok : int;

begin
 parser.m_processor:=@epilogProcessor;
 parser.m_eventPtr :=s;

 repeat
  next:=NIL;
  tok :=XmlPrologTok(parser.m_encoding ,pointer(s ) ,pointer(end_ ) ,@next );

  parser.m_eventEndPtr:=next;

  case tok of
   -XML_TOK_PROLOG_S :
    begin
     if @parser.m_defaultHandler <> NIL then
      begin
       reportDefault(parser ,parser.m_encoding ,s ,next );

       if parser.m_parsingStatus.parsing = XML_FINISHED then
        begin
         result:=XML_ERROR_ABORTED;

         exit;

        end;

      end;

     nextPtr^:=next;
     result  :=XML_ERROR_NONE;

     exit;

    end;

   XML_TOK_NONE :
    begin
     nextPtr^:=s;
     result  :=XML_ERROR_NONE;

     exit;

    end;

   XML_TOK_PROLOG_S :
    if @parser.m_defaultHandler <> NIL then
     reportDefault(parser ,parser.m_encoding ,s ,next );

   XML_TOK_PI :
    if reportProcessingInstruction(parser ,parser.m_encoding ,s ,next ) = 0 then
     begin
      result:=XML_ERROR_NO_MEMORY;

      exit;

     end;

   XML_TOK_COMMENT :
    if reportComment(parser ,parser.m_encoding ,s ,next ) = 0 then
     begin
      result:=XML_ERROR_NO_MEMORY;

      exit;

     end;

   XML_TOK_INVALID :
    begin
     parser.m_eventPtr:=next;

     result:=XML_ERROR_INVALID_TOKEN;

     exit;

    end;

   XML_TOK_PARTIAL :
    begin
     if parser.m_parsingStatus.finalBuffer = 0 then
      begin
       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     result:=XML_ERROR_UNCLOSED_TOKEN;

     exit;

    end;

   XML_TOK_PARTIAL_CHAR :
    begin
     if parser.m_parsingStatus.finalBuffer = 0 then
      begin
       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     result:=XML_ERROR_PARTIAL_CHAR;

     exit;

    end;

   else
    begin
     result:=XML_ERROR_JUNK_AFTER_DOC_ELEMENT;

     exit;

    end;

  end;

  parser.m_eventPtr:=next;

  s:=next;

  case parser.m_parsingStatus.parsing of
   XML_SUSPENDED :
    begin
     nextPtr^:=next;
     result  :=XML_ERROR_NONE;

     exit;

    end;

   XML_FINISHED :
    begin
     result:=XML_ERROR_ABORTED;

     exit;

    end;

  end;

 until false;

end;

{ doCdataSection {..}
{ startPtr gets set to non-null if the section is closed, and to null if
  the section is not yet closed. }
function doCdataSection(
          parser : XML_Parser;
          enc : ENCODING_ptr;
          startPtr : char_ptr_ptr;
          end_ : char_ptr;
          nextPtr : char_ptr_ptr;
          haveMore : XML_Bool ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ cdataSectionProcessor {..}
{ The idea here is to avoid using stack for each CDATA section when
  the whole file is parsed with one call. }
function cdataSectionProcessor(parser : XML_Parser; start ,end_ : char_ptr; endPtr : char_ptr_ptr ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ doContent }
function doContent(
          parser : XML_Parser;
          startTagLevel : int;
          enc : ENCODING_ptr;
          s ,end_ : char_ptr;
          nextPtr : char_ptr_ptr;
          haveMore : XML_Bool ) : XML_Error;
var
 dtd : DTD_ptr;

 eventPP ,eventEndPP : char_ptr_ptr;

 next ,rawNameEnd ,fromPtr ,temp ,rawName : char_ptr;

 tok ,bufSize ,convLen ,len ,n : int;

 c ,ch : XML_Char;

 name ,context ,toPtr ,localPart ,prefix ,uri : XML_Char_ptr;

 entity : ENTITY_ptr;

 result_ : XML_Error;

 tag : TAG_ptr;

 bindings ,b : BINDING_ptr;

 noElmHandlers : XML_Bool;

 name_ : TAG_NAME;

 buf : array[0..XML_ENCODE_MAX - 1 ] of XML_Char;

 dataPtr : ICHAR_ptr;

label
 _break ;

begin
{ save one level of indirection }
 temp:=nil;
 dtd:=parser.m_dtd;

 if enc = parser.m_encoding then
  begin
   eventPP   :=@parser.m_eventPtr;
   eventEndPP:=@parser.m_eventEndPtr;

  end
 else
  begin
   eventPP   :=@parser.m_openInternalEntities.internalEventPtr;
   eventEndPP:=@parser.m_openInternalEntities.internalEventEndPtr;

  end;

 eventPP^:=s;

 repeat
  next:=s; { XmlContentTok doesn't always set the last arg }

  tok:=XmlContentTok(enc ,pointer(s ) ,pointer(end_ ) ,@next );

  eventEndPP^:=next;

  case tok of
   XML_TOK_TRAILING_CR :
    begin
     if haveMore <> 0 then
      begin
       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     eventEndPP^:=end_;

     if @parser.m_characterDataHandler <> NIL then
      begin
       c:=XML_Char($A );

       parser.m_characterDataHandler(parser.m_handlerArg ,@c ,1 );

      end
     else
      if @parser.m_defaultHandler <> NIL then
       reportDefault(parser ,enc ,s ,end_ );

    { We are at the end of the final buffer, should we check for
      XML_SUSPENDED, XML_FINISHED? }
     if startTagLevel = 0 then
      begin
       result:=XML_ERROR_NO_ELEMENTS;

       exit;

      end;

     if parser.m_tagLevel <> startTagLevel then
      begin
       result:=XML_ERROR_ASYNC_ENTITY;

       exit;

      end;

     nextPtr^:=end_;
     result  :=XML_ERROR_NONE;

     exit;

    end;

   XML_TOK_NONE :
    begin
     if haveMore <> 0 then
      begin
       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     if startTagLevel > 0 then
      begin
       if parser.m_tagLevel <> startTagLevel then
        begin
         result:=XML_ERROR_ASYNC_ENTITY;

         exit;

        end;

       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     result:=XML_ERROR_NO_ELEMENTS;

     exit;

    end;

   XML_TOK_INVALID :
    begin
     eventPP^:=next;
     result  :=XML_ERROR_INVALID_TOKEN;

     exit;

    end;

   XML_TOK_PARTIAL :
    begin
     if haveMore <> 0 then
      begin
       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     result:=XML_ERROR_UNCLOSED_TOKEN;

     exit;

    end;

   XML_TOK_PARTIAL_CHAR :
    begin
     if haveMore <> 0 then
      begin
       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     result:=XML_ERROR_PARTIAL_CHAR;

     exit;

    end;

   XML_TOK_ENTITY_REF :
    begin
     ch:=
      XML_Char(XmlPredefinedEntityName(
       enc ,
       pointer(ptrcomp(s ) + enc.minBytesPerChar ) ,
       pointer(ptrcomp(next ) - enc.minBytesPerChar ) ) );

     if ch <> XML_Char(0 ) then
      begin
       if @parser.m_characterDataHandler <> NIL then
        parser.m_characterDataHandler(parser.m_handlerArg ,@ch ,1 )
       else
        if @parser.m_defaultHandler <> NIL then
         reportDefault(parser ,enc ,s ,next );

       goto _break;

      end;

     name:=
      poolStoreString(
       @dtd.pool ,enc ,
       char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
       char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

     if name = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     entity:=ENTITY_ptr(lookup(@dtd.generalEntities ,name ,0 ) );

     poolDiscard(@dtd.pool );

    { First, determine if a check for an existing declaration is needed;
      if yes, check that the entity exists, and that it is internal,
      otherwise call the skipped entity or default handler. }
     if (dtd.hasParamEntityRefs = 0 ) or
        (dtd.standalone <> 0 ) then
      if entity = NIL then
       begin
        result:=XML_ERROR_UNDEFINED_ENTITY;

        exit;

       end
      else
       if entity.is_internal = 0 then
        begin
         result:=XML_ERROR_ENTITY_DECLARED_IN_PE;

         exit;

        end
       else
     else
      if entity = NIL then
       begin
        if @parser.m_skippedEntityHandler <> NIL then
         parser.m_skippedEntityHandler(parser.m_handlerArg ,name ,0 )
        else
         if @parser.m_defaultHandler <> NIL then
          reportDefault(parser ,enc ,s ,next );

        goto _break;

       end;

     if entity.open <> 0 then
      begin
       result:=XML_ERROR_RECURSIVE_ENTITY_REF;

       exit;

      end;

     if entity.notation <> NIL then
      begin
       result:=XML_ERROR_BINARY_ENTITY_REF;

       exit;

      end;

     if entity.textPtr <> NIL then
      begin
       if parser.m_defaultExpandInternalEntities <> 0 then
        begin
         if @parser.m_skippedEntityHandler <> NIL then
          parser.m_skippedEntityHandler(parser.m_handlerArg ,entity.name ,0 )
         else
          if @parser.m_defaultHandler <> NIL then
           reportDefault(parser ,enc ,s ,next );

         goto _break;

        end;

       result_:=processInternalEntity(parser ,entity ,XML_FALSE );

       if result_ <> XML_ERROR_NONE then
        begin
         result:=result_;

         exit;

        end;

      end
     else
      if @parser.m_externalEntityRefHandler <> NIL then
       begin
        entity.open:=XML_TRUE;
        context    :=getContext(parser );
        entity.open:=XML_FALSE;

        if context = NIL then
         begin
          result:=XML_ERROR_NO_MEMORY;

          exit;

         end;

        if parser.m_externalEntityRefHandler(
            parser.m_externalEntityRefHandlerArg ,
            context ,
            entity.base ,
            entity.systemId ,
            entity.publicId ) = 0 then
         begin
          result:=XML_ERROR_EXTERNAL_ENTITY_HANDLING;

          exit;

         end;

        poolDiscard(@parser.m_tempPool );

       end
      else
       if @parser.m_defaultHandler <> NIL then
        reportDefault(parser ,enc ,s ,next );

    end;

   XML_TOK_START_TAG_NO_ATTS ,XML_TOK_START_TAG_WITH_ATTS :
    begin
     if parser.m_freeTagList <> NIL then
      begin
       tag:=parser.m_freeTagList;

       parser.m_freeTagList:=parser.m_freeTagList.parent;

      end
     else
      begin
       parser.m_mem.malloc_fcn(pointer(tag ) ,sizeof(expat.TAG ) );

       if tag = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;
       FillByte(tag^,SizeOf(expat.tag),0); // MG

       parser.m_mem.malloc_fcn(pointer(tag.buf ) ,INIT_TAG_BUF_SIZE );

       if tag.buf = NIL then
        begin
         parser.m_mem.free_fcn(pointer(tag ) ,sizeof(expat.TAG ) );

         result:=XML_ERROR_NO_MEMORY;

         exit;

        end
       else
        tag.alloc:=INIT_TAG_BUF_SIZE;

       tag.bufEnd:=char_ptr(ptrcomp(tag.buf ) + INIT_TAG_BUF_SIZE );

      end;

     tag.bindings      :=NIL;
     tag.parent        :=parser.m_tagStack;
     parser.m_tagStack :=tag;
     tag.name.localPart:=NIL;
     tag.name.prefix   :=NIL;
     tag.rawName       :=char_ptr(ptrcomp(s ) + enc.minBytesPerChar );
     tag.rawNameLength :=XmlNameLength(enc ,pointer(tag.rawName ) );

     inc(parser.m_tagLevel );

     rawNameEnd:=char_ptr(ptrcomp(tag.rawName ) + tag.rawNameLength );
     fromPtr   :=tag.rawName;
     toPtr     :=XML_Char_ptr(tag.buf );

     repeat
      XmlConvert(
       enc ,
       @fromPtr ,rawNameEnd ,
       ICHAR_ptr_ptr(@toPtr ) ,ICHAR_ptr(ptrcomp(tag.bufEnd ) - 1 ) );

      convLen:=(ptrcomp(toPtr ) - ptrcomp(tag.buf ) ) div sizeof(XML_Char );

      if fromPtr = rawNameEnd then
       begin
        tag.name.strLen:=convLen;

        break;

       end;

      bufSize:=(ptrcomp(tag.bufEnd ) - ptrcomp(tag.buf ) ) shl 1;

      parser.m_mem.realloc_fcn(pointer(tag.buf ) ,tag.alloc ,bufSize );

      if temp = NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end
      else
       tag.alloc:=bufSize;

      tag.buf   :=temp;
      tag.bufEnd:=char_ptr(ptrcomp(temp ) + bufSize );

      toPtr:=XML_Char_ptr(ptrcomp(temp ) + convLen );

     until false;

     tag.name.str:=XML_Char_ptr(tag.buf );

     toPtr^ :=XML_T(#0 );
     result_:=storeAtts(parser ,enc ,s ,@tag.name ,@tag.bindings );

     if result_ <> XML_Error(0 ) then
      begin
       result:=result_;

       exit;

      end;
     if @parser.m_startElementHandler <> NIL then
      parser.m_startElementHandler(
       parser.m_handlerArg ,tag.name.str ,
       XML_Char_ptr_ptr(parser.m_atts ) )
     else
      if @parser.m_defaultHandler <> NIL then
       reportDefault(parser ,enc ,s ,next );

     poolClear(@parser.m_tempPool );

    end;

   XML_TOK_EMPTY_ELEMENT_NO_ATTS ,XML_TOK_EMPTY_ELEMENT_WITH_ATTS :
    begin
     rawName      :=char_ptr(ptrcomp(s ) + enc.minBytesPerChar );
     bindings     :=NIL;
     noElmHandlers:=XML_TRUE;

     name_.str:=
      poolStoreString(
       @parser.m_tempPool ,enc ,rawName ,
       char_ptr(ptrcomp(rawName ) + XmlNameLength(enc ,pointer(rawName ) ) ) );

     if name_.str = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     poolFinish(@parser.m_tempPool );
     result_:=storeAtts(parser ,enc ,s ,@name_ ,@bindings );

     if result_ <> XML_Error(0 ) then
      begin
       result:=result_;

       exit;

      end;

     poolFinish(@parser.m_tempPool );

     if @parser.m_startElementHandler <> NIL then
      begin
       parser.m_startElementHandler(
        parser.m_handlerArg ,name_.str ,XML_Char_ptr_ptr(parser.m_atts ) );

       noElmHandlers:=XML_FALSE;

      end;

     if @parser.m_endElementHandler <> NIL then
      begin
       if @parser.m_startElementHandler <> NIL then
        eventPP^:=eventEndPP^;

       parser.m_endElementHandler(parser.m_handlerArg ,name_.str );

       noElmHandlers:=XML_FALSE;

      end;

     if (noElmHandlers <> 0 ) and
        (@parser.m_defaultHandler <> NIL ) then
      reportDefault(parser ,enc ,s ,next );

     poolClear(@parser.m_tempPool );

     while bindings <> NIL do
      begin
       b:=bindings;

       if @parser.m_endNamespaceDeclHandler <> NIL then
        parser.m_endNamespaceDeclHandler(parser.m_handlerArg ,b.prefix.name );

       bindings        :=bindings.nextTagBinding;
       b.nextTagBinding:=parser.m_freeBindingList;

       parser.m_freeBindingList:=b;
       b.prefix.binding        :=b.prevPrefixBinding;

      end;

     if parser.m_tagLevel = 0 then
      begin
       result:=epilogProcessor(parser ,next ,end_ ,nextPtr );

       exit;

      end;

    end;

   XML_TOK_END_TAG :
    if parser.m_tagLevel = startTagLevel then
     begin
      result:=XML_ERROR_ASYNC_ENTITY;

      exit;

     end
    else
     begin
      tag                 :=parser.m_tagStack;
      parser.m_tagStack   :=tag.parent;
      tag.parent          :=parser.m_freeTagList;
      parser.m_freeTagList:=tag;

      rawName:=char_ptr(ptrcomp(s ) + enc.minBytesPerChar * 2 );
      len    :=XmlNameLength(enc ,pointer(rawName ) );

      if (len <> tag.rawNameLength ) or
         (memcmp(pointer(tag.rawName ) ,pointer(rawName ) ,len ) <> 0 ) then
       begin
        eventPP^:=rawName;
        result  :=XML_ERROR_TAG_MISMATCH;

        exit;

       end;

      dec(parser.m_tagLevel );

      if @parser.m_endElementHandler <> NIL then
       begin
        localPart:=tag.name.localPart;

        if (parser.m_ns <> 0 ) and
           (localPart <> NIL ) then
         begin
         { localPart and prefix may have been overwritten in
           tag->name.str, since this points to the binding->uri
           buffer which gets re-used; so we have to add them again }
          uri:=XML_Char_ptr(ptrcomp(tag.name.str ) + tag.name.uriLen );

         { don't need to check for space - already done in storeAtts() }
          while localPart^ <> XML_Char(0 ) do
           begin
            uri^:=localPart^;

            inc(ptrcomp(uri ) ,sizeof(XML_Char ) );
            inc(ptrcomp(localPart ) ,sizeof(XML_Char ) );

           end;

          prefix:=XML_Char_ptr(tag.name.prefix );

          if (parser.m_ns_triplets <> 0 ) and
             (prefix <> NIL ) then
           begin
            uri^:=parser.m_namespaceSeparator;

            inc(ptrcomp(uri ) ,sizeof(XML_Char ) );

            while prefix^ <> XML_Char(0 ) do
             begin
              uri^:=prefix^;

              inc(ptrcomp(uri ) ,sizeof(XML_Char ) );
              inc(ptrcomp(prefix ) ,sizeof(XML_Char ) );

             end;

           end;

          uri^:=XML_T(#0 );

         end;

        parser.m_endElementHandler(parser.m_handlerArg ,tag.name.str );

       end
      else
       if @parser.m_defaultHandler <> NIL then
        reportDefault(parser ,enc ,s ,next );

      while tag.bindings <> NIL do
       begin
        b:=tag.bindings;

        if @parser.m_endNamespaceDeclHandler <> NIL then
         parser.m_endNamespaceDeclHandler(parser.m_handlerArg ,b.prefix.name );

        tag.bindings            :=tag.bindings.nextTagBinding;
        b.nextTagBinding        :=parser.m_freeBindingList;
        parser.m_freeBindingList:=b;
        b.prefix.binding        :=b.prevPrefixBinding;

       end;

      if parser.m_tagLevel = 0 then
       begin
        result:=epilogProcessor(parser ,next ,end_ ,nextPtr );

        exit;

       end;

     end;

   XML_TOK_CHAR_REF :
    begin
     n:=XmlCharRefNumber(enc ,pointer(s ) );

     if n < 0 then
      begin
       result:=XML_ERROR_BAD_CHAR_REF;

       exit;

      end;

     if @parser.m_characterDataHandler <> NIL then
      parser.m_characterDataHandler(
       parser.m_handlerArg ,@buf[0 ] ,
       XmlEncode(n ,ICHAR_ptr(@buf ) ) )
     else
      if @parser.m_defaultHandler <> NIL then
       reportDefault(parser ,enc ,s ,next );

    end;

   XML_TOK_XML_DECL :
    begin
     result:=XML_ERROR_MISPLACED_XML_PI;

     exit;

    end;

   XML_TOK_DATA_NEWLINE :
    if @parser.m_characterDataHandler <> NIL then
     begin
      c:=XML_Char($A );
      parser.m_characterDataHandler(parser.m_handlerArg ,@c ,1 );
     end
    else
     if @parser.m_defaultHandler <> NIL then
      reportDefault(parser ,enc ,s ,next );

   XML_TOK_CDATA_SECT_OPEN :
    begin
     if @parser.m_startCdataSectionHandler <> NIL then
      parser.m_startCdataSectionHandler(parser.m_handlerArg )
    {$IFDEF 0 }
    { Suppose you doing a transformation on a document that involves
      changing only the character data.  You set up a defaultHandler
      and a characterDataHandler.  The defaultHandler simply copies
      characters through.  The characterDataHandler does the
      transformation and writes the characters out escaping them as
      necessary.  This case will fail to work if we leave out the
      following two lines (because & and < inside CDATA sections will
      be incorrectly escaped).

      However, now we have a start/endCdataSectionHandler, so it seems
      easier to let the user deal with this. }
     else
      if @parser.m_characterDataHandler <> NIL then
       parser.m_characterDataHandler(parser.m_handlerArg ,parser.m_dataBuf ,0 )
    {$ENDIF }
     else
      if @parser.m_defaultHandler <> NIL then
       reportDefault(parser ,enc ,s ,next );

     result_:=doCdataSection(parser ,enc ,@next ,end_ ,nextPtr ,haveMore );

     if result_ <> XML_ERROR_NONE then
      begin
       result:=result_;

       exit;

      end
     else
      if next = NIL then
       begin
        parser.m_processor:=@cdataSectionProcessor;

        result:=result_;

        exit;

       end;

    end;

   XML_TOK_TRAILING_RSQB :
    begin
     if haveMore <> 0 then
      begin
       nextPtr^:=s;
       result  :=XML_ERROR_NONE;

       exit;

      end;

     if @parser.m_characterDataHandler <> NIL then
      if MUST_CONVERT(enc ,s ) <> 0 then
       begin
        dataPtr:=ICHAR_ptr(parser.m_dataBuf );

        XmlConvert(enc ,@s ,end_ ,@dataPtr ,ICHAR_ptr(parser.m_dataBufEnd ) );

        parser.m_characterDataHandler(
         parser.m_handlerArg ,
         parser.m_dataBuf ,
         (ptrcomp(dataPtr ) - ptrcomp(parser.m_dataBuf ) ) div sizeof(ICHAR ) );

       end
      else
       parser.m_characterDataHandler(
        parser.m_handlerArg ,
        XML_Char_ptr(s ) ,
        (ptrcomp(end_ ) - ptrcomp(s ) ) div sizeof(XML_Char ) )
     else
      if @parser.m_defaultHandler <> NIL then
       reportDefault(parser ,enc ,s ,end_ );

    { We are at the end of the final buffer, should we check for
      XML_SUSPENDED, XML_FINISHED? }
     if startTagLevel = 0 then
      begin
       eventPP^:=end_;
       result  :=XML_ERROR_NO_ELEMENTS;

       exit;

      end;

     if parser.m_tagLevel <> startTagLevel then
      begin
       eventPP^:=end_;
       result  :=XML_ERROR_ASYNC_ENTITY;

       exit;

      end;

     nextPtr^:=end_;
     result  :=XML_ERROR_NONE;

     exit;

    end;

   XML_TOK_DATA_CHARS :
    if @parser.m_characterDataHandler <> NIL then
     if MUST_CONVERT(enc ,s ) <> 0 then
      repeat
       dataPtr:=ICHAR_ptr(parser.m_dataBuf );

       XmlConvert(enc ,@s ,next ,@dataPtr ,ICHAR_ptr(parser.m_dataBufEnd ) );

       eventEndPP^:=s;

       parser.m_characterDataHandler(
        parser.m_handlerArg ,
        parser.m_dataBuf ,
        (ptrcomp(dataPtr ) - ptrcomp(parser.m_dataBuf ) ) div sizeof(ICHAR ) );

       if s = next then
        break;

       eventPP^:=s;

      until false
     else
      parser.m_characterDataHandler(
       parser.m_handlerArg ,
       XML_Char_ptr(s ) ,
       (ptrcomp(next ) - ptrcomp(s ) ) div sizeof(XML_Char ) )

    else
     if @parser.m_defaultHandler <> NIL then
      reportDefault(parser ,enc ,s ,next );

   XML_TOK_PI :
    if reportProcessingInstruction(parser ,enc ,s ,next ) = 0 then
     begin
      result:=XML_ERROR_NO_MEMORY;

      exit;

     end;

   XML_TOK_COMMENT :
    if reportComment(parser ,enc ,s ,next ) = 0 then
     begin
      result:=XML_ERROR_NO_MEMORY;

      exit;

     end;

   else
    if @parser.m_defaultHandler <> NIL then
     reportDefault(parser ,enc ,s ,next );

  end;

 _break:
  eventPP^:=next;
  s       :=next;

  case parser.m_parsingStatus.parsing of
   XML_SUSPENDED:
    begin
     nextPtr^:=next;
     result  :=XML_ERROR_NONE;

     exit;

    end;

   XML_FINISHED:
    begin
     result:=XML_ERROR_ABORTED;

     exit;

    end;

  end;

 until false;

{ not reached }

end;

{ contentProcessor }
function contentProcessor(parser : XML_Parser; start ,end_ : char_ptr; endPtr : char_ptr_ptr ) : XML_Error;
var
 result_ : XML_Error;

begin
 result_:=
  doContent(
   parser ,0 ,parser.m_encoding ,start ,end_ ,
   endPtr ,XML_Bool(not parser.m_parsingStatus.finalBuffer ) );

 if result_ = XML_ERROR_NONE then
  if storeRawNames(parser ) = 0 then
   begin
    result:=XML_ERROR_NO_MEMORY;

    exit;

   end;

 result:=result_;

end;

{ getElementType {..}
function getElementType(parser : XML_Parser; enc : ENCODING_ptr; ptr ,end_ : char_ptr ) : ELEMENT_TYPE_ptr;
begin
 Result:=0;
end;

{ getAttributeId }
function getAttributeId(parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr ) : ATTRIBUTE_ID_ptr;
var
 dtd : DTD_ptr;

 id : ATTRIBUTE_ID_ptr;

 name : XML_Char_ptr;

 i ,j : int;

begin
{ save one level of indirection }
 dtd:=parser.m_dtd;

 if poolAppendChar(@dtd.pool ,XML_T(#0 ) ) = 0 then
  begin
   result:=NIL;

   exit;

  end;

 name:=poolStoreString(@dtd.pool ,enc ,start ,end_ );

 if name = NIL then
  begin
   result:=NIL;

   exit;

  end;

{ skip quotation mark - its storage will be re-used (like in name[-1]) }
 inc(ptrcomp(name ) ,sizeof(XML_Char ) );

 id:=ATTRIBUTE_ID_ptr(lookup(@dtd.attributeIds ,name ,sizeof(ATTRIBUTE_ID ) ) );

 if id = NIL then
  begin
   result:=NIL;

   exit;

  end;

 if id.name <> name then
  poolDiscard(@dtd.pool )

 else
  begin
   poolFinish(@dtd.pool );

   if parser.m_ns = 0 then
   else
    if (XML_Char_ptr(ptrcomp(name ) + 0 * sizeof(XML_Char ) )^ = XML_T('x' ) ) and
       (XML_Char_ptr(ptrcomp(name ) + 1 * sizeof(XML_Char ) )^ = XML_T('m' ) ) and
       (XML_Char_ptr(ptrcomp(name ) + 2 * sizeof(XML_Char ) )^ = XML_T('l' ) ) and
       (XML_Char_ptr(ptrcomp(name ) + 3 * sizeof(XML_Char ) )^ = XML_T('n' ) ) and
       (XML_Char_ptr(ptrcomp(name ) + 4 * sizeof(XML_Char ) )^ = XML_T('s' ) ) and
       ((XML_Char_ptr(ptrcomp(name ) + 5 * sizeof(XML_Char ) )^ = XML_T(#0 ) ) or
        (XML_Char_ptr(ptrcomp(name ) + 5 * sizeof(XML_Char ) )^ = XML_T(':' ) ) ) then
     begin
      if XML_Char_ptr(ptrcomp(name ) + 5 * sizeof(XML_Char ) )^ = XML_T(#0 ) then
       id.prefix:=@dtd.defaultPrefix
      else
       id.prefix:=PREFIX_ptr(lookup(@dtd.prefixes ,XML_Char_ptr(ptrcomp(name ) + 6 * sizeof(XML_Char ) ) ,sizeof(PREFIX ) ) );

      id.xmlns:=XML_TRUE;

     end
    else
     begin
      i:=0;

      while XML_Char_ptr(ptrcomp(name ) + i * sizeof(XML_Char ) )^ <> XML_Char(0 ) do
       begin
       { attributes without prefix are *not* in the default namespace }
        if XML_Char_ptr(ptrcomp(name ) + i * sizeof(XML_Char ) )^ = XML_T(':' ) then
         begin
          j:=0;

          while j < i do
           begin
            if poolAppendChar(@dtd.pool ,XML_Char_ptr(ptrcomp(name ) + j * sizeof(XML_Char ) )^ ) = 0 then
             begin
              result:=NIL;

              exit;

             end;

            inc(j );

           end;

          if poolAppendChar(@dtd.pool ,XML_T(#0 ) ) = 0 then
           begin
            result:=NIL;

            exit;

           end;

          id.prefix:=
           PREFIX_ptr(
            lookup(@dtd.prefixes ,poolStart(@dtd.pool ) ,sizeof(PREFIX ) ) );

          if id.prefix.name = poolStart(@dtd.pool ) then
           poolFinish(@dtd.pool )
          else
           poolDiscard(@dtd.pool );

          break;

         end;

        inc(i );

       end;

     end;

  end;

 result:=id;

end;

{ defineAttribute {..}
function defineAttribute(
          type_ : ELEMENT_TYPE_ptr; attId : ATTRIBUTE_ID_ptr;
          isCdata ,isId : XML_Bool; value : XML_Char_ptr; parser : XML_Parser ) : int;
begin
 Result:=0;
end;

{ appendAttributeValue }
function appendAttributeValue(
          parser : XML_Parser; enc : ENCODING_ptr; isCdata : XML_Bool;
          ptr ,end_ : char_ptr; pool : STRING_POOL_ptr ) : XML_Error;
var
 dtd : DTD_ptr;

 next : char_ptr;

 tok ,i ,n : int;

 buf : array[0..XML_ENCODE_MAX - 1 ] of XML_Char;

 name ,textEnd : XML_Char_ptr;

 entity : ENTITY_ptr;

 checkEntityDecl : char;

 ch : XML_Char;

 result_ : XML_Error;

label
 _break ,_go0 ; 

begin
{ save one level of indirection }
 dtd:=parser.m_dtd;

 repeat
  tok:=XmlAttributeValueTok(enc ,pointer(ptr ) ,pointer(end_ ) ,@next );

  case tok of
   XML_TOK_NONE :
    begin
     result:=XML_ERROR_NONE;

     exit;

    end;

   XML_TOK_INVALID :
    begin
     if enc = parser.m_encoding then
      parser.m_eventPtr:=next;

     result:=XML_ERROR_INVALID_TOKEN;

    end;

   XML_TOK_PARTIAL :
    begin
     if enc = parser.m_encoding then
      parser.m_eventPtr:=ptr;

     result:=XML_ERROR_INVALID_TOKEN;

    end;

   XML_TOK_CHAR_REF :
    begin
     n:=XmlCharRefNumber(enc ,pointer(ptr ) );

     if n < 0 then
      begin
       if enc = parser.m_encoding then
        parser.m_eventPtr:=ptr;

       result:=XML_ERROR_BAD_CHAR_REF;

      end;

     if (isCdata = 0 ) and
        (n = $20 ) and { space }
        ((poolLength(pool ) = 0 ) or
         (poolLastChar(pool ) = XML_Char($20 ) ) ) then
      goto _break;

     n:=XmlEncode(n ,ICHAR_ptr(buf ) );

     if n = 0 then
      begin
       if enc = parser.m_encoding then
        parser.m_eventPtr:=ptr;

       result:=XML_ERROR_BAD_CHAR_REF;

       exit;

      end;

     i:=0;

     while i < n do
      begin
       if poolAppendChar(pool ,buf[i ] ) = 0 then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       inc(i );

      end;

    end;

   XML_TOK_DATA_CHARS :
    if poolAppend(pool ,enc ,ptr ,next ) = NIL then
     begin
      result:=XML_ERROR_NO_MEMORY;

      exit;

     end;

   XML_TOK_TRAILING_CR :
    begin
     next:=char_ptr(ptrcomp(ptr ) + enc.minBytesPerChar );

     goto _go0;

    end;

   XML_TOK_ATTRIBUTE_VALUE_S ,XML_TOK_DATA_NEWLINE :
   _go0:
    begin
     if (isCdata = 0 ) and
        ((poolLength(pool ) = 0 ) or
         (poolLastChar(pool ) = XML_Char($20 ) ) ) then
      goto _break;

     if poolAppendChar(pool ,char($20 ) ) = 0 then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

    end;

   XML_TOK_ENTITY_REF :
    begin
     ch:=
      XML_Char(
       XmlPredefinedEntityName(
        enc ,
        pointer(char_ptr(ptrcomp(ptr ) + enc.minBytesPerChar ) ) ,
        pointer(char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) ) ) );

     if ch <> XML_Char(0 ) then
      begin
       if poolAppendChar(pool, ch) = 0 then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       goto _break;

      end;

     name:=
      poolStoreString(
       @parser.m_temp2Pool ,enc ,
       char_ptr(ptrcomp(ptr ) + enc.minBytesPerChar ) ,
       char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

     if name = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     entity:=ENTITY_ptr(lookup(@parser.m_dtd.generalEntities ,name ,0 ) );

     poolDiscard(@parser.m_temp2Pool );

    { First, determine if a check for an existing declaration is needed;
      if yes, check that the entity exists, and that it is internal. }
     if pool = @parser.m_dtd.pool then  { are we called from prolog? }
      begin
       if dtd.standalone <> 0 then
        checkEntityDecl:=char(parser.m_openInternalEntities = NIL )
       else
        checkEntityDecl:=char(dtd.hasParamEntityRefs = 0 );

      {$IFDEF XML_DTD }
       checkEntityDecl:=char((checkEntityDecl <> #0 ) and (parser.m_prologState.documentEntity <> 0 ) )

      {$ENDIF }

      end
     else { if pool = @tempPool: we are called from content }
      checkEntityDecl:=char((dtd.hasParamEntityRefs = 0 ) or (dtd.standalone <> 0 ) );

     if checkEntityDecl <> #0 then
      if entity = NIL then
       begin
        result:=XML_ERROR_UNDEFINED_ENTITY;

        exit;

       end
      else
       if entity.is_internal = 0 then
        begin
         result:=XML_ERROR_ENTITY_DECLARED_IN_PE;

         exit;

        end
       else
     else
      if entity = NIL then
      { Cannot report skipped entity here - see comments on
        skippedEntityHandler.
        if @parser.m_skippedEntityHandler <> NIL then
         parser.m_skippedEntityHandler(parser.m_handlerArg ,name ,0 ); }
      { Cannot call the default handler because this would be
        out of sync with the call to the startElementHandler.
        if (pool = @parser.m_tempPool ) and
           (@parser.m_defaultHandler <> NIL ) then
         reportDefault(parser ,enc ,ptr ,next ); }
       goto _break;

     if entity.open <> 0 then
      begin
       if enc = parser.m_encoding then
        parser.m_eventPtr:=ptr;

       result:=XML_ERROR_RECURSIVE_ENTITY_REF;

       exit;

      end;

     if entity.notation <> NIL then
      begin
       if enc = parser.m_encoding then
        parser.m_eventPtr:=ptr;

       result:=XML_ERROR_BINARY_ENTITY_REF;

       exit;

      end;

     if entity.textPtr = NIL then
      begin
       if enc = parser.m_encoding then
        parser.m_eventPtr:=ptr;

       result:=XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;

       exit;

      end
     else
      begin
       textEnd:=XML_Char_ptr(ptrcomp(entity.textPtr ) + entity.textLen * sizeof(XML_Char ) );

       entity.open:=XML_TRUE;

       result_:=
        appendAttributeValue(
         parser ,parser.m_internalEncoding ,isCdata ,
         char_ptr(entity.textPtr ) ,
         char_ptr(textEnd ) ,pool );

       entity.open:=XML_FALSE;

       if result_ <> XML_Error(0 ) then
        begin
         result:=result_;

         exit;

        end;

      end;

    end;

   else
    begin
     if enc = parser.m_encoding then
      parser.m_eventPtr:=ptr;

     result:=XML_ERROR_UNEXPECTED_STATE;

     exit;

    end;

  end;

 _break:
  ptr:=next;

 until false;

{ not reached }

end;

{ storeAttributeValue }
function storeAttributeValue(
          parser : XML_Parser; enc : ENCODING_ptr; isCdata : XML_Bool;
          ptr ,end_ : char_ptr; pool : STRING_POOL_ptr ) : XML_Error;
var
 result_ : XML_Error;

begin
 result_:=appendAttributeValue(parser ,enc ,isCdata ,ptr ,end_ ,pool );

 if result_ <> XML_Error(0 ) then
  begin
   result:=result_;

   exit;

  end;

 if (isCdata = 0 ) and
    (poolLength(pool ) <> 0 ) and
    (poolLastChar(pool ) = XML_Char($20 ) ) then
  poolChop(pool );

 if poolAppendChar(pool ,XML_T(#0 ) ) = 0 then
  begin
   result:=XML_ERROR_NO_MEMORY;

   exit;

  end;

 result:=XML_ERROR_NONE;

end;

{ storeEntityValue {..}
function storeEntityValue(parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ doIgnoreSection {..}
{ startPtr gets set to non-null is the section is closed, and to null
  if the section is not yet closed. }
function doIgnoreSection(
          parser : XML_Parser;
          enc : ENCODING_ptr;
          startPtr : char_ptr_ptr;
          end_ : char_ptr;
          nextPtr : char_ptr_ptr;
          haveMore : XML_Bool ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ ignoreSectionProcessor {..}
{ The idea here is to avoid using stack for each IGNORE section when
  the whole file is parsed with one call. }
function ignoreSectionProcessor(parser : XML_Parser; start ,end_ : char_ptr; endPtr : char_ptr_ptr ) : XML_Error;
begin
 Result:=XML_ERROR_NONE;
end;

{ nextScaffoldPart {..}
function nextScaffoldPart(parser : XML_Parser ) : int;
begin
 Result:=0;
end;

{ build_model {..}
function build_model(parser : XML_Parser ) : XML_Content_ptr;
begin
 Result:=nil;
end;

{ reportProcessingInstruction {..}
function reportProcessingInstruction(parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr ) : int;
begin
 Result:=0;
end;

{ normalizeLines {..}
procedure normalizeLines(s : XML_Char_ptr );
begin
end;

{ reportComment }
function reportComment(parser : XML_Parser; enc : ENCODING_ptr; start ,end_ : char_ptr ) : int;
var
 data : XML_Char_ptr;

begin
 if @parser.m_commentHandler = NIL then
  begin
   if @parser.m_defaultHandler <> NIL then
    reportDefault(parser ,enc ,start ,end_ );

   result:=1;

   exit;

  end;

 data:=
  poolStoreString(
   @parser.m_tempPool ,enc ,
   char_ptr(ptrcomp(start ) + enc.minBytesPerChar * 4 ) ,
   char_ptr(ptrcomp(end_ ) - enc.minBytesPerChar * 3 ) );

 if data = NIL then
  begin
   result:=0;

   exit;

  end;

 normalizeLines(data );

 parser.m_commentHandler(parser.m_handlerArg ,data );

 poolClear(@parser.m_tempPool );

 result:=1;

end;

{ doProlog }
function doProlog(
          parser : XML_Parser;
          enc : ENCODING_ptr;
          s ,end_ : char_ptr;
          tok : int;
          next : char_ptr;
          nextPtr : char_ptr_ptr;
          haveMore : XML_Bool ) : XML_Error;
const
{$IFDEF XML_DTD }
 externalSubsetName : array[0..1 ] of XML_Char = ('#' ,#0 );

{$ENDIF }

 atypeCDATA     : array[0..5 ] of XML_Char = ('C' ,'D' ,'A' ,'T' ,'A' ,#0 );
 atypeID        : array[0..2 ] of XML_Char = ('I' ,'D' ,#0 );
 atypeIDREF     : array[0..5 ] of XML_Char = ('I' ,'D' ,'R' ,'E' ,'F' ,#0 );
 atypeIDREFS    : array[0..6 ] of XML_Char = ('I' ,'D' ,'R' ,'E' ,'F' ,'S' ,#0 );
 atypeENTITY    : array[0..6 ] of XML_Char = ('E' ,'N' ,'T' ,'I' ,'T' ,'Y' ,#0 );
 atypeENTITIES  : array[0..8 ] of XML_Char = ('E' ,'N' ,'T' ,'I' ,'T' ,'I' ,'E' ,'S',#0 );
 atypeNMTOKEN   : array[0..7 ] of XML_Char = ('N' ,'M' ,'T' ,'O' ,'K' ,'E' ,'N' ,#0 );
 atypeNMTOKENS  : array[0..8 ] of XML_Char = ('N' ,'M' ,'T' ,'O' ,'K' ,'E' ,'N' ,'S',#0 );
 notationPrefix : array[0..8 ] of XML_Char = ('N' ,'O' ,'T' ,'A' ,'T' ,'I' ,'O' ,'N',#0 );
 enumValueSep   : array[0..1 ] of XML_Char = ('|' ,#0 );
 enumValueStart : array[0..1 ] of XML_Char = ('(' ,#0 );

var
 dtd : DTD_ptr;

 eventPP ,eventEndPP : char_ptr_ptr;

 quant : XML_Content_Quant;

 role ,myindex ,nameLen : int;

 handleDefault ,hadParamEntityRefs ,ok ,betweenDecl : XML_Bool;

 result_ : XML_Error;

 tem ,prefix ,attVal ,name ,systemId : XML_Char_ptr;

 entity : ENTITY_ptr;

 //ctemp : char_ptr;
 nxt : char_ptr;

 //itemp : int_ptr;

 content ,model : XML_Content_ptr;

 el : ELEMENT_TYPE_ptr;

label
 _break ,_go0 ,_go1 ,
 alreadyChecked ,checkAttListDeclHandler ,elementContent ,closeGroup ;

begin
{ save one level of indirection }
 dtd:=parser.m_dtd;

 if enc = parser.m_encoding then
  begin
   eventPP   :=@parser.m_eventPtr;
   eventEndPP:=@parser.m_eventEndPtr;

  end
 else
  begin
   eventPP   :=@parser.m_openInternalEntities.internalEventPtr;
   eventEndPP:=@parser.m_openInternalEntities.internalEventEndPtr;

  end;

 repeat
  handleDefault:=XML_TRUE;
  eventPP^     :=s;
  eventEndPP^  :=next;

  if tok <= 0 then
   begin
    if (haveMore <> 0 ) and
       (tok <> XML_TOK_INVALID ) then
     begin
      nextPtr^:=s;
      result  :=XML_ERROR_NONE;

      exit;

     end;

    case tok of
     XML_TOK_INVALID :
      begin
       eventPP^:=next;
       result  :=XML_ERROR_INVALID_TOKEN;

       exit;

      end;

     XML_TOK_PARTIAL :
      begin
       result:=XML_ERROR_UNCLOSED_TOKEN;

       exit;

      end;

     XML_TOK_PARTIAL_CHAR :
      begin
       result:=XML_ERROR_PARTIAL_CHAR;

       exit;

      end;

     XML_TOK_NONE :
      begin
      {$IFDEF XML_DTD }
      { for internal PE NOT referenced between declarations }
       if (enc <> parser.m_encoding ) and
          (parser.m_openInternalEntities.betweenDecl = 0 ) then
        begin
         nextPtr^:=s;
         result  :=XML_ERROR_NONE;

         exit;

        end;

      { WFC: PE Between Declarations - must check that PE contains
        complete markup, not only for external PEs, but also for
        internal PEs if the reference occurs between declarations. }
       if (parser.m_isParamEntity <> 0 ) or
          (enc <> parser.m_encoding ) then
        begin
         if XmlTokenRole(@parser.m_prologState ,XML_TOK_NONE ,pointer(end_ ) ,pointer(end_ ) ,enc ) = XML_ROLE_ERROR then
          begin
           result:=XML_ERROR_INCOMPLETE_PE;

           exit;

          end;

         nextPtr^:=s;
         result  :=XML_ERROR_NONE;

         exit;

        end;

      {$ENDIF }

       result:=XML_ERROR_NO_ELEMENTS;

       exit;

      end;

     else
      begin
       tok :=-tok;
       next:=end_;

      end;

    end;

   end;

  role:=XmlTokenRole(@parser.m_prologState ,tok ,pointer(s ) ,pointer(next ) ,enc );

  case role of
   XML_ROLE_XML_DECL :
    begin
     result_:=processXmlDecl(parser ,0 ,s ,next );

     if result_ <> XML_ERROR_NONE then
      begin
       result:=result_;

       exit;

      end;

     enc:=parser.m_encoding;

     handleDefault:=XML_FALSE;

    end;

   XML_ROLE_DOCTYPE_NAME :
    begin
     if @parser.m_startDoctypeDeclHandler <> NIL then
      begin
       parser.m_doctypeName:=poolStoreString(@parser.m_tempPool ,enc ,s ,next );

       if parser.m_doctypeName = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       poolFinish(@parser.m_tempPool );

       parser.m_doctypePubid:=NIL;
       handleDefault        :=XML_FALSE;

      end;

     parser.m_doctypeSysid:=NIL; { always initialize to NULL }

    end;

   XML_ROLE_DOCTYPE_INTERNAL_SUBSET :
    if @parser.m_startDoctypeDeclHandler <> NIL then
     begin
      parser.m_startDoctypeDeclHandler(
       parser.m_handlerArg ,parser.m_doctypeName ,
       parser.m_doctypeSysid ,parser.m_doctypePubid ,1 );

      parser.m_doctypeName:=NIL;

      poolClear(@parser.m_tempPool );

      handleDefault:=XML_FALSE;

     end;

  {$IFDEF XML_DTD }
   XML_ROLE_TEXT_DECL :
    begin
     result_:=processXmlDecl(parser ,1 ,s ,next );

     if result_ <> XML_ERROR_NONE then
      begin
       result:=result_;

       exit;

      end;

     enc          :=parser.m_encoding;
     handleDefault:=XML_FALSE;

    end;

  {$ENDIF }

   XML_ROLE_DOCTYPE_PUBLIC_ID :
    begin
    {$IFDEF XML_DTD }
     parser.m_useForeignDTD:=XML_FALSE;
     parser.m_declEntity   :=
      ENTITY_ptr(
       lookup(@dtd.paramEntities ,@externalSubsetName[0 ] ,sizeof(expat.ENTITY ) ) );

     if parser.m_declEntity = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

    {$ENDIF }
     dtd.hasParamEntityRefs:=XML_TRUE;

     if @parser.m_startDoctypeDeclHandler <> NIL then
      begin
       if XmlIsPublicId(enc ,pointer(s ) ,pointer(next ) ,pointer(eventPP ) ) = 0 then
        begin
         result:=XML_ERROR_PUBLICID;

         exit;

        end;

       parser.m_doctypePubid:=
        poolStoreString(
         @parser.m_tempPool ,enc ,
         char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
         char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

       if parser.m_doctypePubid = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       normalizePublicId(XML_Char_ptr(parser.m_doctypePubid ) );
       poolFinish       (@parser.m_tempPool );

       handleDefault:=XML_FALSE;

       goto alreadyChecked;

      end;

    { fall through }
     goto _go0;

    end;

   XML_ROLE_ENTITY_PUBLIC_ID :
   _go0:
    begin
     if XmlIsPublicId(enc ,pointer(s ) ,pointer(next ) ,pointer(eventPP ) ) = 0 then
      begin
       result:=XML_ERROR_PUBLICID;

       exit;

      end;

    alreadyChecked:
     if (dtd.keepProcessing <> 0 ) and
        (parser.m_declEntity <> NIL ) then
      begin
       tem:=
        poolStoreString(
         @dtd.pool ,enc ,
         char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
         char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

       if tem = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       normalizePublicId(tem );

       parser.m_declEntity.publicId:=tem;

       poolFinish(@dtd.pool );

       if @parser.m_entityDeclHandler <> NIL then
        handleDefault:=XML_FALSE;

      end;

    end;

   XML_ROLE_DOCTYPE_CLOSE :
    begin
     if parser.m_doctypeName <> NIL then
      begin
       parser.m_startDoctypeDeclHandler(
        parser.m_handlerArg ,parser.m_doctypeName ,
        parser.m_doctypeSysid ,parser.m_doctypePubid ,0 );

       poolClear(@parser.m_tempPool );

       handleDefault:=XML_FALSE;

      end;

    { doctypeSysid will be non-NULL in the case of a previous
      XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
      was not set, indicating an external subset }
    {$IFDEF XML_DTD }
     if (parser.m_doctypeSysid <> NIL ) or
        (parser.m_useForeignDTD <> 0 ) then
      begin
       hadParamEntityRefs    :=dtd.hasParamEntityRefs;
       dtd.hasParamEntityRefs:=XML_TRUE;

       if (parser.m_paramEntityParsing <> XML_ParamEntityParsing(0 ) ) and
          (@parser.m_externalEntityRefHandler <> NIL ) then
        begin
         entity:=
          ENTITY_ptr(
           lookup(@dtd.paramEntities ,@externalSubsetName[0 ] ,sizeof(expat.ENTITY ) ) );

         if entity = NIL then
          begin
           result:=XML_ERROR_NO_MEMORY;

           exit;

          end;

         if parser.m_useForeignDTD <> 0 then
          entity.base:=parser.m_curBase;

         dtd.paramEntityRead:=XML_FALSE;

         if parser.m_externalEntityRefHandler(
             parser.m_externalEntityRefHandlerArg ,nil ,
             entity.base ,
             entity.systemId ,
             entity.publicId ) = 0 then
          begin
           result:=XML_ERROR_EXTERNAL_ENTITY_HANDLING;

           exit;

          end;

         if dtd.paramEntityRead <> 0 then
          if (dtd.standalone = 0 ) and
             (@parser.m_notStandaloneHandler <> NIL ) and
             (parser.m_notStandaloneHandler(parser.m_handlerArg ) = 0 ) then
           begin
            result:=XML_ERROR_NOT_STANDALONE;

            exit;

           end
          else
         else
         { if we didn't read the foreign DTD then this means that there
           is no external subset and we must reset dtd.hasParamEntityRefs }
          if parser.m_doctypeSysid = NIL then
           dtd.hasParamEntityRefs:=hadParamEntityRefs;

         { end of DTD - no need to update dtd.keepProcessing }

        end;

       parser.m_useForeignDTD:=XML_FALSE;

      end;

    {$ENDIF }
     if @parser.m_endDoctypeDeclHandler <> NIL then
      begin
       parser.m_endDoctypeDeclHandler(parser.m_handlerArg );

       handleDefault:=XML_FALSE;

      end;

    end;

   XML_ROLE_INSTANCE_START :
    begin
    {$IFDEF XML_DTD }
    { if there is no DOCTYPE declaration then now is the
      last chance to read the foreign DTD }
     if parser.m_useForeignDTD <> 0 then
      begin
       hadParamEntityRefs    :=dtd.hasParamEntityRefs;
       dtd.hasParamEntityRefs:=XML_TRUE;

       if (parser.m_paramEntityParsing <> XML_ParamEntityParsing(0 ) ) and
          (@parser.m_externalEntityRefHandler <> NIL ) then
        begin
         entity:=
          ENTITY_ptr(
           lookup(@dtd.paramEntities ,@externalSubsetName[0 ] ,sizeof(expat.ENTITY ) ) );

         if entity = NIL then
          begin
           result:=XML_ERROR_NO_MEMORY;

           exit;

          end;

         entity.base        :=parser.m_curBase;
         dtd.paramEntityRead:=XML_FALSE;

         if parser.m_externalEntityRefHandler(
             parser.m_externalEntityRefHandlerArg ,nil ,
             entity.base ,
             entity.systemId ,
             entity.publicId ) = 0 then
          begin
           result:=XML_ERROR_EXTERNAL_ENTITY_HANDLING;

           exit;

          end;

         if dtd.paramEntityRead <> 0 then
          if (dtd.standalone = 0 ) and
             (@parser.m_notStandaloneHandler <> NIL ) and
             (parser.m_notStandaloneHandler(parser.m_handlerArg ) = 0 ) then
           begin
            result:=XML_ERROR_NOT_STANDALONE;

            exit;

           end
          else
         else
         { if we didn't read the foreign DTD then this means that there
           is no external subset and we must reset dtd.hasParamEntityRefs }
          dtd.hasParamEntityRefs:=hadParamEntityRefs;

         { end of DTD - no need to update dtd.keepProcessing }

        end;

      end;

    {$ENDIF }
     parser.m_processor:=@contentProcessor;
     result:=contentProcessor(parser ,s ,end_ ,nextPtr );
     exit;

    end;

   XML_ROLE_ATTLIST_ELEMENT_NAME :
    begin
     parser.m_declElementType:=getElementType(parser ,enc ,s ,next );

     if parser.m_declElementType = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_NAME :
    begin
     parser.m_declAttributeId:=getAttributeId(parser ,enc ,s ,next );

     if parser.m_declAttributeId = NIL then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     parser.m_declAttributeIsCdata:=XML_FALSE;
     parser.m_declAttributeType   :=NIL;
     parser.m_declAttributeIsId   :=XML_FALSE;

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_CDATA :
    begin
     parser.m_declAttributeIsCdata:=XML_TRUE;
     parser.m_declAttributeType   :=@atypeCDATA[0 ];

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_ID :
    begin
     parser.m_declAttributeIsId:=XML_TRUE;
     parser.m_declAttributeType:=@atypeID[0 ];

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_IDREF :
    begin
     parser.m_declAttributeType:=@atypeIDREF[0 ];

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_IDREFS :
    begin
     parser.m_declAttributeType:=@atypeIDREFS[0 ];

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_ENTITY :
    begin
     parser.m_declAttributeType:=@atypeENTITY[0 ];

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_ENTITIES :
    begin
     parser.m_declAttributeType:=@atypeENTITIES[0 ];

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN :
    begin
     parser.m_declAttributeType:=@atypeNMTOKEN[0 ];

     goto checkAttListDeclHandler;

    end;

   XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS :
    begin
     parser.m_declAttributeType:=@atypeNMTOKENS[0 ];

    checkAttListDeclHandler:
     if (dtd.keepProcessing <> 0 ) and
        (@parser.m_attlistDeclHandler <> NIL ) then
      handleDefault:=XML_FALSE;

    end;

   XML_ROLE_ATTRIBUTE_ENUM_VALUE ,XML_ROLE_ATTRIBUTE_NOTATION_VALUE :
    if (dtd.keepProcessing <> 0 ) and
       (@parser.m_attlistDeclHandler <> NIL ) then
     begin
      if parser.m_declAttributeType <> NIL  then
       prefix:=@enumValueSep[0 ]

      else
       if role = XML_ROLE_ATTRIBUTE_NOTATION_VALUE then
        prefix:=@notationPrefix[0 ]
       else
        prefix:=@enumValueStart[0 ];

      if poolAppendString(@parser.m_tempPool ,prefix ) = NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      if poolAppend(@parser.m_tempPool ,enc ,s ,next ) = NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      parser.m_declAttributeType:=parser.m_tempPool.start;

      handleDefault:=XML_FALSE;

     end;

   XML_ROLE_IMPLIED_ATTRIBUTE_VALUE ,XML_ROLE_REQUIRED_ATTRIBUTE_VALUE :
    if dtd.keepProcessing <> 0 then
     begin
      if defineAttribute(
          parser.m_declElementType ,parser.m_declAttributeId ,
          parser.m_declAttributeIsCdata ,parser.m_declAttributeIsId ,
          nil ,parser ) = 0 then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      if (@parser.m_attlistDeclHandler <> NIL ) and
         (parser.m_declAttributeType <> NIL ) then
       begin
        if (parser.m_declAttributeType^ = XML_T('(' ) ) or
           ((parser.m_declAttributeType^ = XML_T('N' ) ) and
            (XML_Char_ptr(ptrcomp(parser.m_declAttributeType ) + 1 )^ = XML_T('O' ) ) ) then
         begin
         { Enumerated or Notation type }
          if (poolAppendChar(@parser.m_tempPool ,XML_T(')' ) ) = 0 ) or
             (poolAppendChar(@parser.m_tempPool ,XML_T(#0 ) ) = 0 ) then
           begin
            result:=XML_ERROR_NO_MEMORY;

            exit;

           end;

          parser.m_declAttributeType:=parser.m_tempPool.start;

          poolFinish(@parser.m_tempPool );

         end;

        eventEndPP^:=s;

        parser.m_attlistDeclHandler(
         parser.m_handlerArg ,parser.m_declElementType.name ,
         parser.m_declAttributeId.name ,parser.m_declAttributeType ,
         nil ,int(role = XML_ROLE_REQUIRED_ATTRIBUTE_VALUE ) );

        poolClear(@parser.m_tempPool );

        handleDefault:=XML_FALSE;

       end;

     end;

   XML_ROLE_DEFAULT_ATTRIBUTE_VALUE ,XML_ROLE_FIXED_ATTRIBUTE_VALUE :
    if dtd.keepProcessing <> 0 then
     begin
      result_:=
       storeAttributeValue(
        parser ,enc ,parser.m_declAttributeIsCdata ,
        char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
        char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) ,
        @dtd.pool );

      if result_ <> XML_Error(0 ) then
       begin
        result:=result_;

        exit;

       end;

      attVal:=poolStart(@dtd.pool );

      poolFinish(@dtd.pool );

     { ID attributes aren't allowed to have a default }
      if defineAttribute(
          parser.m_declElementType ,parser.m_declAttributeId ,
          parser.m_declAttributeIsCdata ,XML_FALSE ,attVal ,parser ) = 0 then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      if (@parser.m_attlistDeclHandler <> NIL ) and
         (parser.m_declAttributeType <> NIL ) then
       begin
        if (parser.m_declAttributeType^ = XML_T('(' ) ) or
           ((parser.m_declAttributeType^ = XML_T('N' ) ) and
            (XML_Char_ptr(ptrcomp(parser.m_declAttributeType ) + 1 )^ = XML_T('O' ) ) ) then
         begin
         { Enumerated or Notation type }
          if (poolAppendChar(@parser.m_tempPool ,XML_T(')' ) ) = 0 ) or
             (poolAppendChar(@parser.m_tempPool ,XML_T(#0 ) ) = 0 ) then
           begin
            result:=XML_ERROR_NO_MEMORY;

            exit;

           end;

          parser.m_declAttributeType:=parser.m_tempPool.start;

          poolFinish(@parser.m_tempPool );

         end;

        eventEndPP^:=s;

        parser.m_attlistDeclHandler(
         parser.m_handlerArg ,parser.m_declElementType.name ,
         parser.m_declAttributeId.name ,parser.m_declAttributeType ,
         attVal ,int(role = XML_ROLE_FIXED_ATTRIBUTE_VALUE ) );

        poolClear(@parser.m_tempPool );

        handleDefault:=XML_FALSE;

       end;

     end;

   XML_ROLE_ENTITY_VALUE :
    if dtd.keepProcessing <> 0 then
     begin
      result_:=
       storeEntityValue(
        parser ,enc ,
        char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
        char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

      if parser.m_declEntity <> NIL then
       begin
        parser.m_declEntity.textPtr:=poolStart(@dtd.entityValuePool );
        parser.m_declEntity.textLen:=poolLength(@dtd.entityValuePool );

        poolFinish(@dtd.entityValuePool );

        if @parser.m_entityDeclHandler <> NIL then
         begin
          eventEndPP^:=s;

          parser.m_entityDeclHandler(
           parser.m_handlerArg ,
           parser.m_declEntity.name,
           parser.m_declEntity.is_param,
           parser.m_declEntity.textPtr,
           parser.m_declEntity.textLen,
           parser.m_curBase ,nil ,nil ,nil );

          handleDefault:=XML_FALSE;

         end;

       end
      else
       poolDiscard(@dtd.entityValuePool );

      if result_ <> XML_ERROR_NONE then
       begin
        result:=result_;

        exit;

       end;

     end;

   XML_ROLE_DOCTYPE_SYSTEM_ID :
    begin
    {$IFDEF XML_DTD }
     parser.m_useForeignDTD:=XML_FALSE;

    {$ENDIF }

     dtd.hasParamEntityRefs:=XML_TRUE;

     if @parser.m_startDoctypeDeclHandler <> NIL then
      begin
       parser.m_doctypeSysid:=
        poolStoreString(
         @parser.m_tempPool ,enc ,
         char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
         char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

       if parser.m_doctypeSysid = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       poolFinish(@parser.m_tempPool );

       handleDefault:=XML_FALSE;

      end
    {$IFDEF XML_DTD }
     else
     { use externalSubsetName to make doctypeSysid non-NULL
       for the case where no startDoctypeDeclHandler is set }
      parser.m_doctypeSysid:=@externalSubsetName[0 ];

    {$ELSE }; {$ENDIF }

     if (dtd.standalone = 0 ) and
       {$IFDEF XML_DTD }
        (parser.m_paramEntityParsing = XML_ParamEntityParsing(0 ) ) and
       {$ENDIF }
        (@parser.m_notStandaloneHandler <> NIL ) and
        (parser.m_notStandaloneHandler(parser.m_handlerArg ) = 0 ) then
      begin
       result:=XML_ERROR_NOT_STANDALONE;

       exit;

      end;

    {$IFNDEF XML_DTD }
    {$ELSE }
     if parser.m_declEntity = NIL then
      begin
       parser.m_declEntity:=
        ENTITY_ptr(
         lookup(
          @dtd.paramEntities ,@externalSubsetName[0 ] ,sizeof(expat.ENTITY ) ) );

       if parser.m_declEntity = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       parser.m_declEntity.publicId:=NIL;

      end;

    {$ENDIF }
    { fall through }
     goto _go1;

    end;

   XML_ROLE_ENTITY_SYSTEM_ID :
   _go1:
    if (dtd.keepProcessing <> 0 ) and
       (parser.m_declEntity <> NIL ) then
     begin
      parser.m_declEntity.systemId:=
       poolStoreString(
        @dtd.pool ,enc ,
        char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
        char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

      if parser.m_declEntity.systemId = NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      parser.m_declEntity.base:=parser.m_curBase;

      poolFinish(@dtd.pool );

      if @parser.m_entityDeclHandler <> NIL then
       handleDefault:=XML_FALSE;

     end;

   XML_ROLE_ENTITY_COMPLETE :
    if (dtd.keepProcessing <> 0 ) and
       (parser.m_declEntity <> NIL ) and
       (@parser.m_entityDeclHandler <> NIL ) then
     begin
      eventEndPP^:=s;

      parser.m_entityDeclHandler(
       parser.m_handlerArg ,
       parser.m_declEntity.name ,
       parser.m_declEntity.is_param ,
       nil ,0 ,
       parser.m_declEntity.base ,
       parser.m_declEntity.systemId ,
       parser.m_declEntity.publicId ,
       nil );

      handleDefault:=XML_FALSE;

     end;

   XML_ROLE_ENTITY_NOTATION_NAME :
    if (dtd.keepProcessing <> 0 ) and
       (parser.m_declEntity <> NIL ) then
     begin
      parser.m_declEntity.notation:=poolStoreString(@dtd.pool ,enc ,s ,next );

      if parser.m_declEntity.notation = NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      poolFinish(@dtd.pool );

      if @parser.m_unparsedEntityDeclHandler <> NIL then
       begin
        eventEndPP^:=s;

        parser.m_unparsedEntityDeclHandler(
         parser.m_handlerArg ,
         parser.m_declEntity.name ,
         parser.m_declEntity.base ,
         parser.m_declEntity.systemId ,
         parser.m_declEntity.publicId ,
         parser.m_declEntity.notation );

        handleDefault:=XML_FALSE;

       end
      else
       if @parser.m_entityDeclHandler <> NIL then
        begin
         eventEndPP^:=s;

         parser.m_entityDeclHandler(
          parser.m_handlerArg ,
          parser.m_declEntity.name ,
          0 ,nil ,0 ,
          parser.m_declEntity.base,
          parser.m_declEntity.systemId ,
          parser.m_declEntity.publicId ,
          parser.m_declEntity.notation );

         handleDefault:=XML_FALSE;

        end;

     end;

   XML_ROLE_GENERAL_ENTITY_NAME :
    begin
     if XmlPredefinedEntityName(enc ,pointer(s ) ,pointer(next ) ) <> 0 then
      begin
       parser.m_declEntity:=NIL;

       goto _break;
       
      end;

     if dtd.keepProcessing <> 0 then
      begin
       name:=poolStoreString(@dtd.pool ,enc ,s ,next );

       if name = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       parser.m_declEntity:=
        ENTITY_ptr(
         lookup(@dtd.generalEntities ,name ,sizeof(expat.ENTITY ) ) );

       if parser.m_declEntity = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       if parser.m_declEntity.name <> name then
        begin
         poolDiscard(@dtd.pool );

         parser.m_declEntity:=NIL;

        end
       else
        begin
         poolFinish(@dtd.pool );

         parser.m_declEntity.publicId:=NIL;
         parser.m_declEntity.is_param:=XML_FALSE;

        { if we have a parent parser or are reading an internal parameter
          entity, then the entity declaration is not considered "internal" }
         parser.m_declEntity.is_internal:=
          XML_Bool(
           not ((parser.m_parentParser <> NIL ) or
                (parser.m_openInternalEntities <> NIL ) ) );

         if @parser.m_entityDeclHandler <> NIL then
          handleDefault:=XML_FALSE;

        end;

      end
     else
      begin
       poolDiscard(@dtd.pool );

       parser.m_declEntity:=NIL;

      end;

    end;

   XML_ROLE_PARAM_ENTITY_NAME :
   {$IFDEF XML_DTD }
    if dtd.keepProcessing <> 0 then
     begin
      name:=poolStoreString(@dtd.pool ,enc ,s ,next );

      if name <> NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      parser.m_declEntity:=
       ENTITY_ptr(
        lookup(@dtd.paramEntities ,name ,sizeof(expat.ENTITY ) ) );

      if parser.m_declEntity = NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      if parser.m_declEntity.name <> name then
       begin
        poolDiscard(@dtd.pool );

        parser.m_declEntity:=NIL;

       end
      else
       begin
        poolFinish(@dtd.pool );

        parser.m_declEntity.publicId:=NIL;
        parser.m_declEntity.is_param:=XML_TRUE;

       { if we have a parent parser or are reading an internal parameter
         entity, then the entity declaration is not considered "internal" }
        parser.m_declEntity.is_internal:=
         XML_Bool(
          not((parser.m_parentParser <> NIL ) or
              (parser.m_openInternalEntities <> NIL ) ) );

        if @parser.m_entityDeclHandler <> NIL then
         handleDefault:=XML_FALSE;

       end;

     end
    else
     begin
      poolDiscard(@dtd.pool );

      parser.m_declEntity:=NIL;

     end;

   {$ELSE }
    parser.m_declEntity:=NIL;

   {$ENDIF }

   XML_ROLE_NOTATION_NAME :
    begin
     parser.m_declNotationPublicId:=NIL;
     parser.m_declNotationName    :=NIL;

     if @parser.m_notationDeclHandler <> NIL then
      begin
       parser.m_declNotationName:=poolStoreString(@parser.m_tempPool ,enc ,s ,next );

       if parser.m_declNotationName = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       poolFinish(@parser.m_tempPool );

       handleDefault:=XML_FALSE;

      end;

    end;

   XML_ROLE_NOTATION_PUBLIC_ID :
    begin
     if XmlIsPublicId(enc ,pointer(s ) ,pointer(next ) ,pointer(eventPP ) ) = 0 then
      begin
       result:=XML_ERROR_PUBLICID;

       exit;

      end;

     if parser.m_declNotationName <> NIL then { means notationDeclHandler <> NIL }
      begin
       tem:=
        poolStoreString(
         @parser.m_tempPool ,
         enc ,
         char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
         char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

       if tem = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       normalizePublicId(tem );

       parser.m_declNotationPublicId:=tem;

       poolFinish(@parser.m_tempPool );

       handleDefault:=XML_FALSE;

      end;

    end;

   XML_ROLE_NOTATION_SYSTEM_ID :
    begin
     if (parser.m_declNotationName <> NIL ) and
        (@parser.m_notationDeclHandler <> NIL ) then
      begin
       systemId:=
        poolStoreString(
         @parser.m_tempPool ,enc ,
         char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
         char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

       if systemId = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       eventEndPP^:=s;

       parser.m_notationDeclHandler(
        parser.m_handlerArg ,
        parser.m_declNotationName ,
        parser.m_curBase ,
        systemId ,
        parser.m_declNotationPublicId );

       handleDefault:=XML_FALSE;

      end;

     poolClear(@parser.m_tempPool );

    end;

   XML_ROLE_NOTATION_NO_SYSTEM_ID :
    begin
     if (parser.m_declNotationPublicId <> NIL ) and
        (@parser.m_notationDeclHandler <> NIL ) then
      begin
       eventEndPP^:=s;

       parser.m_notationDeclHandler(
        parser.m_handlerArg ,
        parser.m_declNotationName ,
        parser.m_curBase ,
        nil ,
        parser.m_declNotationPublicId );

       handleDefault:=XML_FALSE;

      end;

     poolClear(@parser.m_tempPool );

    end;

   XML_ROLE_ERROR :
    case tok of
     XML_TOK_PARAM_ENTITY_REF :
     { PE references in internal subset are
       not allowed within declarations. }
      begin
       result:=XML_ERROR_PARAM_ENTITY_REF;

       exit;

      end;

     XML_TOK_XML_DECL :
      begin
       result:=XML_ERROR_MISPLACED_XML_PI;

       exit;

      end;

     else
      begin
       result:=XML_ERROR_SYNTAX;

       exit;

      end;

    end;

  {$IFDEF XML_DTD }
   XML_ROLE_IGNORE_SECT :
    begin
     if @parser.m_defaultHandler <> NIL then
      reportDefault(parser ,enc ,s ,next );

     handleDefault:=XML_FALSE;

     result_:=doIgnoreSection(parser ,enc ,@next ,end_ ,nextPtr ,haveMore );

     if result_ <> XML_ERROR_NONE then
      begin
       result:=result_;

       exit;

      end
     else
      if next = NIL then
       begin
        parser.m_processor:=@ignoreSectionProcessor;

        result:=result_;

        exit;

       end;

    end;

  {$ENDIF }

   XML_ROLE_GROUP_OPEN :
    begin
     if parser.m_prologState.level >= parser.m_groupSize then
      if parser.m_groupSize <> 0 then
       begin
        parser.m_groupSize:=parser.m_groupSize * 2;

        if parser.m_mem.realloc_fcn(
            pointer(parser.m_groupConnector ) ,
            parser.m_groupAlloc ,
            parser.m_groupSize ) then
         parser.m_groupAlloc:=parser.m_groupSize

        else
         begin
          result:=XML_ERROR_NO_MEMORY;

          exit;

         end;

        if dtd.scaffIndex <> NIL then
         if parser.m_mem.realloc_fcn(
             pointer(dtd.scaffIndex ) ,
             dtd.scaffAlloc ,
             parser.m_groupSize * sizeof(int ) ) then
          dtd.scaffAlloc:=parser.m_groupSize * sizeof(int )

         else
          begin
           result:=XML_ERROR_NO_MEMORY;

           exit;

          end;

       end
      else
       begin
        parser.m_groupSize:=32;

        if parser.m_mem.malloc_fcn(
            pointer(parser.m_groupConnector ) ,
            parser.m_groupSize ) then
         parser.m_groupAlloc:=parser.m_groupSize

        else
         begin
          result:=XML_ERROR_NO_MEMORY;

          exit;

         end;

       end;

     char_ptr(ptrcomp(parser.m_groupConnector ) + parser.m_prologState.level )^:=#0;

     if dtd.in_eldecl <> 0 then
      begin
       myindex:=nextScaffoldPart(parser );

       if myindex < 0 then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       int_ptr(ptrcomp(dtd.scaffIndex ) + dtd.scaffLevel * sizeof(int ) )^:=myindex;

       inc(dtd.scaffLevel );

       CONTENT_SCAFFOLD_ptr(ptrcomp(dtd.scaffold ) + myindex * sizeof(CONTENT_SCAFFOLD ) )^.type_:=XML_CTYPE_SEQ;

       if @parser.m_elementDeclHandler <> NIL then
        handleDefault:=XML_FALSE;

      end;

    end;

   XML_ROLE_GROUP_SEQUENCE :
    begin
     if char_ptr(ptrcomp(parser.m_groupConnector ) + parser.m_prologState.level )^ = '|' then
      begin
       result:=XML_ERROR_SYNTAX;

       exit;

      end;

     char_ptr(ptrcomp(parser.m_groupConnector ) + parser.m_prologState.level )^:=',';

     if (dtd.in_eldecl <> 0 ) and
        (@parser.m_elementDeclHandler <> NIL ) then
      handleDefault:=XML_FALSE;

    end;

   XML_ROLE_GROUP_CHOICE :
    begin
     if char_ptr(ptrcomp(parser.m_groupConnector ) + parser.m_prologState.level )^ = ',' then
      begin
       result:=XML_ERROR_SYNTAX;

       exit;

      end;

     if (dtd.in_eldecl <> 0 ) and
        (char_ptr(ptrcomp(parser.m_groupConnector ) + parser.m_prologState.level )^ <> #0 ) and
        (CONTENT_SCAFFOLD_ptr(
          ptrcomp(dtd.scaffold ) +
          int_ptr(ptrcomp(dtd.scaffIndex ) + (dtd.scaffLevel - 1 ) * sizeof(int ) )^ *
          sizeof(CONTENT_SCAFFOLD ) )^.type_ <> XML_CTYPE_MIXED ) then
      begin
       CONTENT_SCAFFOLD_ptr(
        ptrcomp(dtd.scaffold ) +
        int_ptr(ptrcomp(dtd.scaffIndex ) + (dtd.scaffLevel - 1 ) * sizeof(int ) )^ *
        sizeof(CONTENT_SCAFFOLD ) )^.type_:=XML_CTYPE_CHOICE;

       if @parser.m_elementDeclHandler <> NIL then
        handleDefault:=XML_FALSE;

      end;

     char_ptr(ptrcomp(parser.m_groupConnector ) + parser.m_prologState.level )^:='|';

    end;

   XML_ROLE_PARAM_ENTITY_REF {$IFDEF XML_DTD } ,XML_ROLE_INNER_PARAM_ENTITY_REF : {$ELSE }: {$ENDIF }
    begin
    {$IFDEF XML_DTD }
     dtd.hasParamEntityRefs:=XML_TRUE;

     if parser.m_paramEntityParsing = XML_ParamEntityParsing(0 ) then
      dtd.keepProcessing:=dtd.standalone

     else
      begin
       name:=
        poolStoreString(
         @dtd.pool ,enc ,
         char_ptr(ptrcomp(s ) + enc.minBytesPerChar ) ,
         char_ptr(ptrcomp(next ) - enc.minBytesPerChar ) );

       if name = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       entity:=ENTITY_ptr(lookup(@dtd.paramEntities ,name ,0 ) );

       poolDiscard(@dtd.pool );

      { first, determine if a check for an existing declaration is needed;
        if yes, check that the entity exists, and that it is internal,
        otherwise call the skipped entity handler }
       if dtd.standalone <> 0 then
        ok:=XML_Bool(parser.m_openInternalEntities = NIL )
       else
        ok:=XML_Bool(dtd.hasParamEntityRefs = 0 );

       if (parser.m_prologState.documentEntity <> 0 ) and
          (ok <> 0 ) then
        if entity = NIL then
         begin
          result:=XML_ERROR_UNDEFINED_ENTITY;

          exit;

         end
        else
         if entity.is_internal = 0 then
          begin
           result:=XML_ERROR_ENTITY_DECLARED_IN_PE;

           exit;

          end
         else
       else
        if entity = NIL then
         begin
          dtd.keepProcessing:=dtd.standalone;

         { cannot report skipped entities in declarations }
          if (role = XML_ROLE_PARAM_ENTITY_REF ) and
             (@parser.m_skippedEntityHandler <> NIL ) then
           begin
            parser.m_skippedEntityHandler(parser.m_handlerArg ,name ,1 );

            handleDefault:=XML_FALSE;

           end;

          goto _break;

         end;

       if entity.open <> 0 then
        begin
         result:=XML_ERROR_RECURSIVE_ENTITY_REF;

         exit;

        end;

       if entity.textPtr <> NIL then
        begin
         if role = XML_ROLE_PARAM_ENTITY_REF then
          betweenDecl:=XML_TRUE
         else
          betweenDecl:=XML_FALSE;

         result_:=processInternalEntity(parser ,entity ,betweenDecl );

         if result_ <> XML_ERROR_NONE then
          begin
           result:=result_;

           exit;

          end;

         handleDefault:=XML_FALSE;

         goto _break;

        end;

       if @parser.m_externalEntityRefHandler <> NIL then
        begin
         dtd.paramEntityRead:=XML_FALSE;
         entity.open        :=XML_TRUE;

         if parser.m_externalEntityRefHandler(
             parser.m_externalEntityRefHandlerArg ,
             nil ,
             entity.base ,
             entity.systemId ,
             entity.publicId ) = 0 then
          begin
           entity.open:=XML_FALSE;

           result:=XML_ERROR_EXTERNAL_ENTITY_HANDLING;

           exit;

          end;

         entity.open  :=XML_FALSE;
         handleDefault:=XML_FALSE;

         if dtd.paramEntityRead = 0 then
          begin
           dtd.keepProcessing:=dtd.standalone;

           goto _break;

          end;

        end
       else
        begin
         dtd.keepProcessing:=dtd.standalone;

         goto _break;

        end;

      end;

    {$ENDIF }

     if (dtd.standalone = 0 ) and
        (@parser.m_notStandaloneHandler <> NIL ) and
        (parser.m_notStandaloneHandler(parser.m_handlerArg ) = 0 ) then
      begin
       result:=XML_ERROR_NOT_STANDALONE;

       exit;

      end;

    end;

  { Element declaration stuff }
   XML_ROLE_ELEMENT_NAME :
    if @parser.m_elementDeclHandler <> NIL then
     begin
      parser.m_declElementType:=getElementType(parser ,enc ,s ,next );

      if parser.m_declElementType = NIL then
       begin
        result:=XML_ERROR_NO_MEMORY;

        exit;

       end;

      dtd.scaffLevel:=0;
      dtd.scaffCount:=0;
      dtd.in_eldecl :=XML_TRUE;
      handleDefault :=XML_FALSE;

     end;

   XML_ROLE_CONTENT_ANY ,XML_ROLE_CONTENT_EMPTY :
    if dtd.in_eldecl <> 0 then
     begin
      if @parser.m_elementDeclHandler <> NIL then
       begin
        content:=nil;
        parser.m_mem.malloc_fcn(pointer(content ) ,sizeof(XML_Content ) );

        if content = NIL then
         begin
          result:=XML_ERROR_NO_MEMORY;

          exit;

         end;

        content.quant      :=XML_CQUANT_NONE;
        content.name       :=NIL;
        content.numchildren:=0;
        content.children   :=NIL;

        if role = XML_ROLE_CONTENT_ANY then
         content.type_:=XML_CTYPE_ANY
        else
         content.type_:=XML_CTYPE_EMPTY;

        eventEndPP^:=s;

        parser.m_elementDeclHandler(
         parser.m_handlerArg ,parser.m_declElementType.name ,content );

        handleDefault:=XML_FALSE;

       end;

      dtd.in_eldecl:=XML_FALSE;

     end;

   XML_ROLE_CONTENT_PCDATA :
    if dtd.in_eldecl <> 0 then
     begin
      CONTENT_SCAFFOLD_ptr(
       ptrcomp(dtd.scaffold ) +
       int_ptr(ptrcomp(dtd.scaffIndex ) + (dtd.scaffLevel - 1 ) * sizeof(int ) )^ *
       sizeof(CONTENT_SCAFFOLD ) )^.type_:=XML_CTYPE_MIXED;

      if @parser.m_elementDeclHandler <> NIL then
       handleDefault:=XML_FALSE;

     end;

   XML_ROLE_CONTENT_ELEMENT :
    begin
     quant:=XML_CQUANT_NONE;

     goto elementContent;

    end;

   XML_ROLE_CONTENT_ELEMENT_OPT :
    begin
     quant:=XML_CQUANT_OPT;

     goto elementContent;

    end;

   XML_ROLE_CONTENT_ELEMENT_REP :
    begin
     quant:=XML_CQUANT_REP;

     goto elementContent;

    end;

   XML_ROLE_CONTENT_ELEMENT_PLUS :
    begin
     quant:=XML_CQUANT_PLUS;

    elementContent:
     if dtd.in_eldecl <> 0 then
      begin
       if quant = XML_CQUANT_NONE then
        nxt:=next
       else
        nxt:=char_ptr(ptrcomp(next ) - enc.minBytesPerChar );

       myindex:=nextScaffoldPart(parser );

       if myindex < 0 then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       CONTENT_SCAFFOLD_ptr(
        ptrcomp(dtd.scaffold ) +
        myindex * sizeof(CONTENT_SCAFFOLD ) )^.type_:=XML_CTYPE_NAME;

       CONTENT_SCAFFOLD_ptr(
        ptrcomp(dtd.scaffold ) +
        myindex * sizeof(CONTENT_SCAFFOLD ) )^.quant:=quant;

       el:=getElementType(parser ,enc ,s ,nxt );

       if el = NIL then
        begin
         result:=XML_ERROR_NO_MEMORY;

         exit;

        end;

       name:=el.name;

       CONTENT_SCAFFOLD_ptr(
        ptrcomp(dtd.scaffold ) +
        myindex * sizeof(CONTENT_SCAFFOLD ) )^.name:=name;

       nameLen:=0;

       while XML_Char_ptr(ptrcomp(name ) + nameLen )^ <> XML_Char(0 ) do
        inc(nameLen );

       inc(dtd.contentStringLen ,nameLen );

       if @parser.m_elementDeclHandler <> NIL then
        handleDefault:=XML_FALSE;

      end;

    end;

   XML_ROLE_GROUP_CLOSE :
    begin
     quant:=XML_CQUANT_NONE;

     goto closeGroup;

    end;

   XML_ROLE_GROUP_CLOSE_OPT :
    begin
     quant:=XML_CQUANT_OPT;

     goto closeGroup;

    end;

   XML_ROLE_GROUP_CLOSE_REP :
    begin
     quant:=XML_CQUANT_REP;

     goto closeGroup;

    end;

   XML_ROLE_GROUP_CLOSE_PLUS :
    begin
     quant:=XML_CQUANT_PLUS;

    closeGroup:
     if dtd.in_eldecl <> 0 then
      begin
       if @parser.m_elementDeclHandler <> NIL then
        handleDefault:=XML_FALSE;

       dec(dtd.scaffLevel );

       CONTENT_SCAFFOLD_ptr(
        ptrcomp(dtd.scaffold ) +
        int_ptr(ptrcomp(dtd.scaffIndex ) + dtd.scaffLevel * sizeof(int ) )^ *
        sizeof(CONTENT_SCAFFOLD) )^.quant:=quant;

       if dtd.scaffLevel = 0 then
        begin
         if handleDefault = 0 then
          begin
           model:=build_model(parser );

           if model = NIL then
            begin
             result:=XML_ERROR_NO_MEMORY;

             exit;

            end;

           eventEndPP^:=s;

           parser.m_elementDeclHandler(
            parser.m_handlerArg ,
            parser.m_declElementType.name ,model );

          end;

         dtd.in_eldecl       :=XML_FALSE;
         dtd.contentStringLen:=0;

        end;

      end;

    end; { End element declaration stuff }

   XML_ROLE_PI :
    begin
     if reportProcessingInstruction(parser ,enc ,s ,next ) = 0 then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     handleDefault:=XML_FALSE;

    end;

   XML_ROLE_COMMENT :
    begin
     if reportComment(parser ,enc ,s ,next ) = 0 then
      begin
       result:=XML_ERROR_NO_MEMORY;

       exit;

      end;

     handleDefault:=XML_FALSE;

    end;

   XML_ROLE_NONE :
    case tok of
     XML_TOK_BOM :
      handleDefault:=XML_FALSE;

    end;

   XML_ROLE_DOCTYPE_NONE :
    if @parser.m_startDoctypeDeclHandler <> NIL then
     handleDefault:=XML_FALSE;

   XML_ROLE_ENTITY_NONE :
    if (dtd.keepProcessing <> 0 ) and
       (@parser.m_entityDeclHandler <> NIL ) then
     handleDefault:=XML_FALSE;

   XML_ROLE_NOTATION_NONE :
    if @parser.m_notationDeclHandler <> NIL then
     handleDefault:=XML_FALSE;

   XML_ROLE_ATTLIST_NONE :
    if (dtd.keepProcessing <> 0 ) and
       (@parser.m_attlistDeclHandler <> NIL ) then
     handleDefault:=XML_FALSE;

   XML_ROLE_ELEMENT_NONE :
    if @parser.m_elementDeclHandler <> NIL then
     handleDefault:=XML_FALSE;

  end; { end of big case }

 _break:
  if (handleDefault = XML_TRUE ) and
     (@parser.m_defaultHandler <> NIL ) then
   reportDefault(parser ,enc ,s ,next );

  case parser.m_parsingStatus.parsing of
   XML_SUSPENDED :
    begin
     nextPtr^:=next;
     result  :=XML_ERROR_NONE;

     exit;

    end;

   XML_FINISHED :
    begin
     result:=XML_ERROR_ABORTED;

     exit;

    end;

   else
    begin
     s  :=next;
     tok:=XmlPrologTok(enc ,pointer(s ) ,pointer(end_ ) ,@next );

    end;

  end;

 until false;

{ not reached }

end;

{ prologProcessor }
function prologProcessor(parser : XML_Parser; s ,end_ : char_ptr; nextPtr : char_ptr_ptr ) : XML_Error;
var
 next : char_ptr;
 tok  : int;

begin
 next:=s;
 tok :=XmlPrologTok(parser.m_encoding ,pointer(s ) ,pointer(end_ ) ,@next );
 result:=
  doProlog(
   parser ,parser.m_encoding ,s ,end_ ,tok ,next ,
   nextPtr ,XML_Bool(not parser.m_parsingStatus.finalBuffer ) );
end;

{ prologInitProcessor }
function prologInitProcessor(parser : XML_Parser; s ,end_ : char_ptr; nextPtr : char_ptr_ptr ) : XML_Error;
var
 result_ : XML_Error;

begin
 result_:=initializeEncoding(parser );

 if result_ <> XML_ERROR_NONE then
  begin
   result:=result_;

   exit;

  end;

 parser.m_processor:=@prologProcessor;

 result:=prologProcessor(parser ,s ,end_ ,nextPtr );

end;

{ parserInit }
procedure parserInit(parser : XML_Parser; encodingName : XML_Char_ptr );
begin
 parser.m_processor:=@prologInitProcessor;

 XmlPrologStateInit(@parser.m_prologState );

 if encodingName <> NIL then
  parser.m_protocolEncodingName:=poolCopyString(@parser.m_tempPool ,encodingName )
 else
  parser.m_protocolEncodingName:=NIL;

 parser.m_curBase:=NIL;

 XmlInitEncoding(@parser.m_initEncoding ,@parser.m_encoding ,nil );

 parser.m_userData  :=NIL;
 parser.m_handlerArg:=NIL;

 parser.m_startElementHandler         :=NIL;
 parser.m_endElementHandler           :=NIL;
 parser.m_characterDataHandler        :=NIL;
 parser.m_processingInstructionHandler:=NIL;
 parser.m_commentHandler              :=NIL;
 parser.m_startCdataSectionHandler    :=NIL;
 parser.m_endCdataSectionHandler      :=NIL;
 parser.m_defaultHandler              :=NIL;
 parser.m_startDoctypeDeclHandler     :=NIL;
 parser.m_endDoctypeDeclHandler       :=NIL;
 parser.m_unparsedEntityDeclHandler   :=NIL;
 parser.m_notationDeclHandler         :=NIL;
 parser.m_startNamespaceDeclHandler   :=NIL;
 parser.m_endNamespaceDeclHandler     :=NIL;
 parser.m_notStandaloneHandler        :=NIL;
 parser.m_externalEntityRefHandler    :=NIL;
 parser.m_externalEntityRefHandlerArg :=parser;
 parser.m_skippedEntityHandler        :=NIL;
 parser.m_elementDeclHandler          :=NIL;
 parser.m_attlistDeclHandler          :=NIL;
 parser.m_entityDeclHandler           :=NIL;
 parser.m_xmlDeclHandler              :=NIL;

 parser.m_bufferPtr:=parser.m_buffer;
 parser.m_bufferEnd:=parser.m_buffer;

 parser.m_parseEndByteIndex:=0;
 parser.m_parseEndPtr      :=NIL;

 parser.m_declElementType:=NIL;
 parser.m_declAttributeId:=NIL;
 parser.m_declEntity     :=NIL;

 parser.m_doctypeName :=NIL;
 parser.m_doctypeSysid:=NIL;
 parser.m_doctypePubid:=NIL;

 parser.m_declAttributeType   :=NIL;
 parser.m_declNotationName    :=NIL;
 parser.m_declNotationPublicId:=NIL;
 parser.m_declAttributeIsCdata:=XML_FALSE;
 parser.m_declAttributeIsId   :=XML_FALSE;

 fillchar(parser.m_position ,sizeof(POSITION ) ,0 );

 parser.m_errorCode:=XML_ERROR_NONE;

 parser.m_eventPtr   :=NIL;
 parser.m_eventEndPtr:=NIL;
 parser.m_positionPtr:=NIL;

 parser.m_openInternalEntities         :=NIL;
 parser.m_defaultExpandInternalEntities:=XML_TRUE;

 parser.m_tagLevel         :=0;
 parser.m_tagStack         :=NIL;
 parser.m_inheritedBindings:=NIL;
 parser.m_nSpecifiedAtts   :=0;

 parser.m_unknownEncodingMem    :=NIL;
 parser.m_unknownEncodingRelease:=NIL;
 parser.m_unknownEncodingData   :=NIL;
 parser.m_unknownEncodingAlloc  :=0;

 parser.m_parentParser         :=NIL;
 parser.m_parsingStatus.parsing:=XML_INITIALIZED;

{$IFDEF XML_DTD }
 parser.m_isParamEntity:=XML_FALSE;
 parser.m_useForeignDTD:=XML_FALSE;

 parser.m_paramEntityParsing:=XML_PARAM_ENTITY_PARSING_NEVER;

{$ENDIF }

end;

{ parserCreate }
function parserCreate(
          encodingName : XML_Char_ptr;
          memsuite : XML_Memory_Handling_Suite_ptr;
          nameSep : XML_Char_ptr;
          dtd : DTD_ptr ) : XML_Parser;
var
 parser : XML_Parser;
 mtemp  : XML_Memory_Handling_Suite_ptr;

begin
 parser:=NIL;

 if memsuite <> NIL then
  begin
   memsuite.malloc_fcn(pointer(parser ) ,sizeof(XML_ParserStruct ) );

   if parser <> NIL then
    begin
     mtemp:=@parser.m_mem;

     mtemp.malloc_fcn :=memsuite.malloc_fcn;
     mtemp.realloc_fcn:=memsuite.realloc_fcn;
     mtemp.free_fcn   :=memsuite.free_fcn;

    end;

  end
 else
  begin
   expat_getmem(pointer(parser ) ,sizeof(XML_ParserStruct ) );

   if parser <> NIL then
    begin
     mtemp:=@parser.m_mem;

     mtemp.malloc_fcn :=@expat_getmem;
     mtemp.realloc_fcn:=@expat_realloc;
     mtemp.free_fcn   :=@expat_freemem;

    end;

  end;

 if parser = NIL then
  begin
   result:=NIL;

   exit;

  end;

 parser.m_buffer   :=NIL;
 parser.m_bufferLim:=NIL;
 parser.m_attsSize :=INIT_ATTS_SIZE;

 parser.m_attsAlloc  :=0;
 parser.m_nsAttsAlloc:=0;

 parser.m_mem.malloc_fcn(pointer(parser.m_atts ) ,parser.m_attsSize * sizeof(ATTRIBUTE ) );

 if parser.m_atts = NIL then
  begin
   parser.m_mem.free_fcn(pointer(parser ) ,sizeof(XML_ParserStruct ) );

   result:=NIL;

   exit;

  end
 else
  parser.m_attsAlloc:=parser.m_attsSize * sizeof(ATTRIBUTE );

 parser.m_mem.malloc_fcn(pointer(parser.m_dataBuf ) ,INIT_DATA_BUF_SIZE * sizeof(XML_Char ) );

 if parser.m_dataBuf = NIL then
  begin
   parser.m_mem.free_fcn(pointer(parser.m_atts ) ,parser.m_attsAlloc );
   parser.m_mem.free_fcn(pointer(parser ) ,sizeof(XML_ParserStruct ) );

   result:=NIL;

   exit;

  end;

 parser.m_dataBufEnd:=XML_Char_ptr(ptrcomp(parser.m_dataBuf ) + INIT_DATA_BUF_SIZE );

 if dtd <> NIL then
  parser.m_dtd:=dtd
 else
  begin
   parser.m_dtd:=dtdCreate(@parser.m_mem );

   if parser.m_dtd = NIL then
    begin
     parser.m_mem.free_fcn(pointer(parser.m_dataBuf ) ,INIT_DATA_BUF_SIZE * sizeof(XML_Char ) );
     parser.m_mem.free_fcn(pointer(parser.m_atts ) ,parser.m_attsAlloc );
     parser.m_mem.free_fcn(pointer(parser ) ,sizeof(XML_ParserStruct ) );

     result:=NIL;

     exit;

    end;

  end;

 parser.m_freeBindingList     :=NIL;
 parser.m_freeTagList         :=NIL;
 parser.m_freeInternalEntities:=NIL;

 parser.m_groupSize     :=0;
 parser.m_groupAlloc    :=0;
 parser.m_groupConnector:=NIL;

 parser.m_unknownEncodingHandler    :=NIL;
 parser.m_unknownEncodingHandlerData:=NIL;

 parser.m_namespaceSeparator:='!';

 parser.m_ns         :=XML_FALSE;
 parser.m_ns_triplets:=XML_FALSE;

 parser.m_nsAtts       :=NIL;
 parser.m_nsAttsVersion:=0;
 parser.m_nsAttsPower  :=0;

 poolInit  (@parser.m_tempPool ,@parser.m_mem );
 poolInit  (@parser.m_temp2Pool ,@parser.m_mem );
 parserInit(parser ,encodingName );

 if (encodingName <> NIL ) and
    (parser.m_protocolEncodingName = NIL ) then
  begin
   XML_ParserFree(parser );

   result:=NIL;

   exit;

  end;

 if nameSep <> NIL then
  begin
   parser.m_ns:=XML_TRUE;

   parser.m_internalEncoding  :=XmlGetInternalEncodingNS;
   parser.m_namespaceSeparator:=nameSep^;

  end
 else
  parser.m_internalEncoding:=XmlGetInternalEncoding;

 result:=parser;

end;

{ setContext {..}
function setContext(parser : XML_Parser; context : XML_Char_ptr ) : XML_Bool;
begin
 Result:=0;
end;

{ XML_PARSERCREATE }
function XML_ParserCreate;
begin
 result:=XML_ParserCreate_MM(encoding ,NIL ,NIL );

end;

{ XML_PARSER_CREATE_MM }
function XML_ParserCreate_MM;
var
 parser : XML_Parser;

begin
 parser:=parserCreate(encoding ,memsuite ,namespaceSeparator ,NIL );

 if (parser <> NIL ) and
    (parser.m_ns <> 0 ) then
 { implicit context only set for root parser, since child
   parsers (i.e. external entity parsers) will inherit it }
  if not setContext(parser ,@implicitContext[0 ] ) <> 0 then
   begin
    XML_ParserFree(parser );

    result:=NIL;

    exit;

   end;

 result:=parser;

end;

{ XML_SETUSERDATA }
procedure XML_SetUserData;
begin
 if parser.m_handlerArg = parser.m_userData then
  begin
   parser.m_handlerArg:=userData;
   parser.m_userData  :=userData;

  end
 else
  parser.m_userData:=userData;

end;

{ XML_SETELEMENTHANDLER }
procedure XML_SetElementHandler;
begin
 parser.m_startElementHandler:=start;
 parser.m_endElementHandler  :=end_;

end;

{ XML_SETCHARACTERDATAHANDLER }
procedure XML_SetCharacterDataHandler;
begin
 parser.m_characterDataHandler:=handler;

end;

{ XML_GetBuffer }
function XML_GetBuffer(parser : XML_Parser; len : int ) : pointer;
var
 neededSize ,keep ,offset ,bufferSize : int;

 newBuf : char_ptr;

begin
 case parser.m_parsingStatus.parsing of
  XML_SUSPENDED :
   begin
    parser.m_errorCode:=XML_ERROR_SUSPENDED;

    result:=NIL;

    exit;

   end;

  XML_FINISHED :
   begin
    parser.m_errorCode:=XML_ERROR_FINISHED;

    result:=NIL;

    exit;

   end;

 end;

 if len > ptrcomp(parser.m_bufferLim ) - ptrcomp(parser.m_bufferEnd ) then
  begin
  { FIXME avoid integer overflow }
   neededSize:=len + (ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) );

  {$IFDEF XML_CONTEXT_BYTES }
   keep:=ptrcomp(parser.m_bufferPtr ) - ptrcomp(parser.m_buffer );

   if keep > _XML_CONTEXT_BYTES then
    keep:=_XML_CONTEXT_BYTES;

   inc(neededSize ,keep );

  {$ENDIF }

   if neededSize <= ptrcomp(parser.m_bufferLim ) - ptrcomp(parser.m_buffer ) then
    begin
    {$IFDEF XML_CONTEXT_BYTES }
     if keep < ptrcomp(parser.m_bufferPtr ) - ptrcomp(parser.m_buffer ) then
      begin
       offset:=ptrcomp(parser.m_bufferPtr ) - ptrcomp(parser.m_buffer ) - keep;

       move(
        char_ptr(ptrcomp(parser.m_buffer ) + offset )^ ,
        parser.m_buffer^ ,
        ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) + keep );

       dec(ptrcomp(parser.m_bufferEnd ) ,offset );
       dec(ptrcomp(parser.m_bufferPtr ) ,offset );

      end;

    {$ELSE }
     move(
      parser.m_bufferPtr^ ,
      parser.m_buffer^ ,
      ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) );

     parser.m_bufferEnd:=char_ptr(ptrcomp(parser.m_buffer ) + (ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) ) );
     parser.m_bufferPtr:=parser.m_buffer;

    {$ENDIF }

    end
   else
    begin
     bufferSize:=ptrcomp(parser.m_bufferLim ) - ptrcomp(parser.m_bufferPtr );

     if bufferSize = 0 then
      bufferSize:=INIT_BUFFER_SIZE;

     repeat
      bufferSize:=bufferSize * 2;

     until bufferSize >= neededSize;

     newBuf:=nil;
     parser.m_mem.malloc_fcn(pointer(newBuf ) ,bufferSize );

     if newBuf = NIL then
      begin
       parser.m_errorCode:=XML_ERROR_NO_MEMORY;

       result:=NIL;

       exit;

      end;

     parser.m_bufferLim :=char_ptr(ptrcomp(newBuf ) + bufferSize );

    {$IFDEF XML_CONTEXT_BYTES }
     if parser.m_bufferPtr <> NIL then
      begin
       keep:=ptrcomp(parser.m_bufferPtr ) - ptrcomp(parser.m_buffer );

       if keep > _XML_CONTEXT_BYTES then
        keep:=_XML_CONTEXT_BYTES;

       move(
        char_ptr(ptrcomp(parser.m_bufferPtr ) - keep )^ ,
        newBuf^ ,
        ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) + keep );

       expat_freemem(pointer(parser.m_buffer ) ,parser.m_bufferAloc );

       parser.m_buffer    :=newBuf;
       parser.m_bufferAloc:=bufferSize;

       parser.m_bufferEnd:=
        char_ptr(
         ptrcomp(parser.m_buffer ) +
         (ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) ) +
         keep );

       parser.m_bufferPtr:=char_ptr(ptrcomp(parser.m_buffer ) + keep );

      end
     else
      begin
       parser.m_bufferEnd :=char_ptr(ptrcomp(newBuf ) + (ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) ) );
       parser.m_buffer    :=newBuf;
       parser.m_bufferPtr :=newBuf;
       parser.m_bufferAloc:=bufferSize;
       
      end;

    {$ELSE }
     if parser.m_bufferPtr <> NIL then
      begin
       move(
        parser.m_bufferPtr^ ,
        newBuf^ ,
        ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) );

       expat_freemem(pointer(parser.m_buffer ) ,parser.m_bufferAloc );

      end;

     parser.m_bufferEnd :=char_ptr(ptrcomp(newBuf ) + (ptrcomp(parser.m_bufferEnd ) - ptrcomp(parser.m_bufferPtr ) ) );
     parser.m_buffer    :=newBuf;
     parser.m_bufferPtr :=newBuf;
     parser.m_bufferAloc:=bufferSize;

    {$ENDIF }

    end;

  end;

 result:=parser.m_bufferEnd;

end;

{ errorProcessor }
function errorProcessor(parser : XML_Parser; s ,end_ : char_ptr; nextPtr : char_ptr_ptr ) : XML_Error;
begin
 result:=parser.m_errorCode;

end;

{ XML_ParseBuffer }
function XML_ParseBuffer(parser : XML_Parser; len ,isFinal : int ) : XML_Status;
var
 start   : char_ptr;
 result_ : XML_Status;

begin
 result_:=XML_STATUS_OK;

 case parser.m_parsingStatus.parsing of
  XML_SUSPENDED :
   begin
    parser.m_errorCode:=XML_ERROR_SUSPENDED;

    result:=XML_STATUS_ERROR;

    exit;

   end;

  XML_FINISHED :
   begin
    parser.m_errorCode:=XML_ERROR_FINISHED;

    result:=XML_STATUS_ERROR;

    exit;

   end;

  else
   parser.m_parsingStatus.parsing:=XML_PARSING_;

 end;

 start               :=parser.m_bufferPtr;
 parser.m_positionPtr:=start;

 inc(ptrcomp(parser.m_bufferEnd ) ,len );

 parser.m_parseEndPtr:=parser.m_bufferEnd;

 inc(ptrcomp(parser.m_parseEndByteIndex ) ,len );

 parser.m_parsingStatus.finalBuffer:=XML_Bool(isFinal );
 parser.m_errorCode:=parser.m_processor(parser ,start ,parser.m_parseEndPtr ,@parser.m_bufferPtr );

 if parser.m_errorCode <> XML_ERROR_NONE then
  begin
   parser.m_eventEndPtr:=parser.m_eventPtr;
   parser.m_processor  :=@errorProcessor;

   result:=XML_STATUS_ERROR;

   exit;

  end
 else
  case parser.m_parsingStatus.parsing of
   XML_SUSPENDED :
    result_:=XML_STATUS_SUSPENDED;

   XML_INITIALIZED ,XML_PARSING_ :
    if isFinal <> 0 then
     begin
      parser.m_parsingStatus.parsing:=XML_FINISHED;

      result:=result_;

      exit;

     end;

   else
   { should not happen }
    NoP;

  end;

 parser.m_encoding.updatePosition(
  parser.m_encoding ,
  pointer(parser.m_positionPtr ) ,
  pointer(parser.m_bufferPtr ) ,@parser.m_position );

 parser.m_positionPtr:=parser.m_bufferPtr;

 result:=result_;

end;

{ XML_PARSE {..}
function XML_Parse;
var
 buff : pointer;

begin
 case parser.m_parsingStatus.parsing of
  XML_SUSPENDED :
   begin
    parser.m_errorCode:=XML_ERROR_SUSPENDED;

    result:=XML_STATUS_ERROR;

    exit;

   end;

  XML_FINISHED :
   begin
    parser.m_errorCode:=XML_ERROR_FINISHED;

    result:=XML_STATUS_ERROR;

    exit;

   end;

  else
   parser.m_parsingStatus.parsing:=XML_PARSING_;

 end;

 if len = 0 then
  begin
   NoP;

  end
{$IFNDEF XML_CONTEXT_BYTES }
 else
  if parser.m_bufferPtr = parser.m_bufferEnd then
   begin
    NoP;

   end

{$ENDIF }
  else
   begin
    buff:=XML_GetBuffer(parser ,len );

    if buff = NIL then
     result:=XML_STATUS_ERROR
     
    else
     begin
      move(s^ ,buff^ ,len );

      result:=XML_ParseBuffer(parser ,len ,isFinal );

     end;
     
   end;

end;

{ XML_GETERRORCODE {..}
function XML_GetErrorCode;
begin
 Result:=XML_ERROR_NO_MEMORY;
end;

{ XML_ERRORSTRING {..}
function XML_ErrorString;
begin
 Result:=nil;
end;

{ XML_GETCURRENTLINENUMBER {..}
function XML_GetCurrentLineNumber;
begin
 Result:=0;
end;

{ destroyBindings }
procedure destroyBindings(bindings : BINDING_ptr; parser : XML_Parser );
var
 b : BINDING_ptr;

begin
 repeat
  b:=bindings;

  if b = NIL then
   break;

  bindings:=b.nextTagBinding;

  parser.m_mem.free_fcn(pointer(b.uri ) ,b.uriAlloc );
  parser.m_mem.free_fcn(pointer(b ) ,sizeof(expat.BINDING ) );

 until false;

end;

{ XML_PARSERFREE }
procedure XML_ParserFree;
var
 tagList ,p : TAG_ptr;

 entityList ,openEntity : OPEN_INTERNAL_ENTITY_ptr;

begin
 if parser = NIL then
  exit;

{ free tagStack and freeTagList }
 tagList:=parser.m_tagStack;

 repeat
  if tagList = NIL then
   begin
    if parser.m_freeTagList = NIL then
     break;

    tagList:=parser.m_freeTagList;

    parser.m_freeTagList:=NIL;

   end;

  p      :=tagList;
  tagList:=tagList.parent;

  parser.m_mem.free_fcn(pointer(p.buf ) ,p.alloc );
  destroyBindings      (p.bindings ,parser );
  parser.m_mem.free_fcn(pointer(p ) ,sizeof(expat.TAG ) );

 until false;

{ free openInternalEntities and freeInternalEntities }
 entityList:=parser.m_openInternalEntities;

 repeat
  if entityList = NIL then
   begin
    if parser.m_freeInternalEntities = NIL then
     break;

    entityList:=parser.m_freeInternalEntities;
    
    parser.m_freeInternalEntities:=NIL;

   end;

  openEntity:=entityList;
  entityList:=entityList.next;

  parser.m_mem.free_fcn(pointer(openEntity ) ,sizeof(OPEN_INTERNAL_ENTITY ) );

 until false;

 destroyBindings(parser.m_freeBindingList ,parser );
 destroyBindings(parser.m_inheritedBindings ,parser );

 poolDestroy(@parser.m_tempPool );
 poolDestroy(@parser.m_temp2Pool );

{$IFDEF XML_DTD }
{ external parameter entity parsers share the DTD structure
  parser->m_dtd with the root parser, so we must not destroy it }
 if (parser.m_isParamEntity = 0 ) and
    (parser.m_dtd <> NIL ) then
{$ELSE }
 if parser.m_dtd <> NIL then{$ENDIF }
  dtdDestroy(parser.m_dtd ,XML_Bool(parser.m_parentParser = NIL ),@parser.m_mem );

 parser.m_mem.free_fcn(pointer(parser.m_atts ) ,parser.m_attsAlloc );
 parser.m_mem.free_fcn(pointer(parser.m_groupConnector ) ,parser.m_groupAlloc );
 parser.m_mem.free_fcn(pointer(parser.m_buffer ) ,parser.m_bufferAloc );
 parser.m_mem.free_fcn(pointer(parser.m_dataBuf ) ,INIT_DATA_BUF_SIZE * sizeof(XML_Char ) );
 parser.m_mem.free_fcn(pointer(parser.m_nsAtts ) ,parser.m_nsAttsAlloc );
 parser.m_mem.free_fcn(pointer(parser.m_unknownEncodingMem ) ,parser.m_unknownEncodingAlloc );

 if @parser.m_unknownEncodingRelease <> NIL then
  parser.m_unknownEncodingRelease(parser.m_unknownEncodingData );

 parser.m_mem.free_fcn(pointer(parser ) ,sizeof(XML_ParserStruct ) );

end;

