2
0
Эх сурвалжийг харах

* implemented highspeed str to float (xml schema types)

git-svn-id: trunk@14113 -
ivost 15 жил өмнө
parent
commit
0b57ceef21
1 өөрчлөгдсөн 215 нэмэгдсэн , 99 устгасан
  1. 215 99
      packages/libxml/src/xmlxsd.pas

+ 215 - 99
packages/libxml/src/xmlxsd.pas

@@ -12,6 +12,7 @@ interface
 
 uses
   xml2,
+  Math,
   DateUtils,
   SysUtils;
 
@@ -499,75 +500,129 @@ begin
   {$warning not implemented}
 end;
 
-function xsdTryParseString(Chars, Last: xmlCharPtr; out Value: String): Boolean;
-var
-  Len: Integer;
+function __parseNonNegativeInteger(var P: PChar; const L: PChar; out Value: QWord): Boolean;
 begin
-  if Assigned(Chars) then
-    if Assigned(Last) then
-    begin
-      Len := Last-Chars+1;
-      if Len > 0 then
-      begin
-        SetLength(Value, Len);
-        Move(Chars^, Value[1], Len);
-        Result := True;
-      end else
-        Result := False;
-    end else begin
-      Value := PChar(Chars);
-      Result := True;
-    end
-  else
-    Result := False;
+  { expect integer }
+  Value := 0;
+  while (P <= L) and (P^ in ['0'..'9']) do
+  begin
+    Value := 10*Value + Ord(P^) - Ord('0');
+    Inc(P);
+  end;
+
+  Result := True;
 end;
 
-function __strpas(Chars, Last: xmlCharPtr): String;
+function __parseInteger(var P: PChar; const L: PChar; out Value: Int64): Boolean;
+var
+  N: Boolean;
 begin
-  if not xsdTryParseString(Chars, Last, Result) then
-    Result := '';
+  { allow '-' }
+  N := (P <= L) and (P^ = '-');
+  if N then
+    Inc(P);
+
+  { expect integer }
+  Value := 0;
+  while (P <= L) and (P^ in ['0'..'9']) do
+  begin
+    Value := 10*Value + Ord(P^) - Ord('0');
+    Inc(P);
+  end;
+  if N then
+    Value := -Value;
+
+  Result := True;
 end;
 
-function xsdTryParseBoolean(Chars, Last: xmlCharPtr; out Value: Boolean): Boolean;
+function __parseFloat(var P: PChar; const L: PChar; out Value: Extended): Boolean;
 var
-  P: PChar;
-  L: PChar absolute Last;
-  Num: QWord;
-  Len: Integer;
+  N: Boolean;
+  Exp: Int64;
+  Int: QWord;
 begin
-  if not Assigned(Last) then
+  { allow 'Nan' }
+  if (P+2 <= L) and ((P^ = 'N') or (P^ = 'n')) then
   begin
-    P := PChar(Chars);
-    Len := 0;
-    while (Len < 7) and (P^ <> #0) do
+    Inc(P);
+    if (P^ <> 'A') and (P^ <> 'a') then Exit(False);
+    Inc(P);
+    if (P^ <> 'N') and (P^ <> 'n') then Exit(False);
+    Inc(P);
+    Value := Nan;
+    Result := True;
+    Exit;
+  end;
+
+  { allow '-' }
+  N := (P <= L) and (P^ = '-');
+  if N then
+    Inc(P);
+
+  { allow 'Inf' }
+  if (P+2 <= L) and ((P^ = 'I') or (P^ = 'i')) then
+  begin
+    Inc(P);
+    if (P^ <> 'N') and (P^ <> 'n') then Exit(False);
+    Inc(P);
+    if (P^ <> 'F') and (P^ <> 'f') then Exit(False);
+    Inc(P);
+    if N then
+      Value := NegInfinity
+    else
+      Value := Infinity;
+    Result := True;
+    Exit;
+  end;
+
+  { expect integer }
+  Int := 0;
+  while (P <= L) and (P^ in ['0'..'9']) do
+  begin
+    Int := 10*Int + Ord(P^) - Ord('0');
+    Inc(P);
+  end;
+  Value := Int;
+  if N then
+    Value := -Value;
+
+  { allow '.' }
+  if (P <= L) and (P^ = '.') then
+  begin
+    Inc(P);
+
+    { expect integer }
+    Exp := 1;
+    Int := 0;
+    while (P <= L) and (P^ in ['0'..'9']) do
     begin
-      Inc(Len);
+      Int := 10*Int + Ord(P^) - Ord('0');
+      Exp := 10*Exp;
       Inc(P);
     end;
-  end else
-    Len := Last-Chars+1;
-
-  case Len of
-    1: Num := PByte(Chars)^;
-    4: Num := PLongword(Chars)^;
-    5: Num := PLongword(Chars)^ or (QWord(Chars[4]) shl 32);
-    else Exit(False);
+    Value := Value + Int / Exp;
   end;
 
-  //writeln(Len, ', ', IntToHex(Num,16));
+  { allow 'E' or 'e' }
+  if (P <= L) and ((P^ = 'E') or (P^ = 'e')) then
+  begin
+    Inc(P);
 
-  case Num of
-    $30,
-    $65736C6166,$65736C6146,$65736C4166,$65736C4146,$65734C6166,$65734C6146,$65734C4166,$65734C4146,
-    $65536C6166,$65536C6146,$65536C4166,$65536C4146,$65534C6166,$65534C6146,$65534C4166,$65534C4146,
-    $45736C6166,$45736C6146,$45736C4166,$45736C4146,$45734C6166,$45734C6146,$45734C4166,$45734C4146,
-    $45536C6166,$45536C6146,$45536C4166,$45536C4146,$45534C6166,$45534C6146,$45534C4166,$45534C4146:
-      Value := False;
-    $31,
-    $65757274,$65757254,$65755274,$65755254,$65557274,$65557254,$65555274,$65555254,
-    $45757274,$45757254,$45755274,$45755254,$45557274,$45557254,$45555274,$45555254:
-      Value := True;
-    else Exit(False);
+    { expect integer }
+    if not __parseInteger(P, L, Exp) then
+      Exit(False);
+
+    while Exp > 0 do
+    begin
+      Value := Value * 10;
+      Dec(Exp);
+    end;
+
+    while Exp < 0 do
+    begin
+      Value := Value * 0.1;
+      Inc(Exp);
+    end;
   end;
 
   Result := True;
@@ -737,14 +792,14 @@ begin
   begin
     Inc(P);
 
-    { expect Integer }
-    Milliseconds := 0;
-    while (P <= L) and (P^ in ['0'..'9']) do
+    { expect integer }
+    Milliseconds := 0; I := 4;
+    while (P <= L) and (P^ in ['0'..'9']) and (I > 0) do
     begin
       Milliseconds := 10*Milliseconds + Ord(P^) - Ord('0');
-      Inc(P);
+      Dec(I); Inc(P);
     end;
-    if (Hour = 24) and (Milliseconds > 0) then
+    if (Milliseconds > 999) or ((Hour = 24) and (Milliseconds > 0)) then
       Exit(False);
   end else
     Milliseconds := 0;
@@ -752,6 +807,80 @@ begin
   Result := True;
 end;
 
+function xsdTryParseString(Chars, Last: xmlCharPtr; out Value: String): Boolean;
+var
+  Len: Integer;
+begin
+  if Assigned(Chars) then
+    if Assigned(Last) then
+    begin
+      Len := Last-Chars+1;
+      if Len > 0 then
+      begin
+        SetLength(Value, Len);
+        Move(Chars^, Value[1], Len);
+        Result := True;
+      end else
+        Result := False;
+    end else begin
+      Value := PChar(Chars);
+      Result := True;
+    end
+  else
+    Result := False;
+end;
+
+function __strpas(Chars, Last: xmlCharPtr): String;
+begin
+  if not xsdTryParseString(Chars, Last, Result) then
+    Result := '';
+end;
+
+function xsdTryParseBoolean(Chars, Last: xmlCharPtr; out Value: Boolean): Boolean;
+var
+  P: PChar;
+  L: PChar absolute Last;
+  Num: QWord;
+  Len: Integer;
+begin
+  if not Assigned(Last) then
+  begin
+    P := PChar(Chars);
+    Len := 0;
+    while (Len < 7) and (P^ <> #0) do
+    begin
+      Inc(Len);
+      Inc(P);
+    end;
+  end else
+    Len := Last-Chars+1;
+
+  case Len of
+    1: Num := PByte(Chars)^;
+    4: Num := PLongword(Chars)^;
+    5: Num := PLongword(Chars)^ or (QWord(Chars[4]) shl 32);
+    else Exit(False);
+  end;
+
+  //writeln(Len, ', ', IntToHex(Num,16));
+
+  case Num of
+    $30,
+    $65736C6166,$65736C6146,$65736C4166,$65736C4146,$65734C6166,$65734C6146,$65734C4166,$65734C4146,
+    $65536C6166,$65536C6146,$65536C4166,$65536C4146,$65534C6166,$65534C6146,$65534C4166,$65534C4146,
+    $45736C6166,$45736C6146,$45736C4166,$45736C4146,$45734C6166,$45734C6146,$45734C4166,$45734C4146,
+    $45536C6166,$45536C6146,$45536C4166,$45536C4146,$45534C6166,$45534C6146,$45534C4166,$45534C4146:
+      Value := False;
+    $31,
+    $65757274,$65757254,$65755274,$65755254,$65557274,$65557254,$65555274,$65555254,
+    $45757274,$45757254,$45755274,$45755254,$45557274,$45557254,$45555274,$45555254:
+      Value := True;
+    else Exit(False);
+  end;
+
+  Result := True;
+end;
+
 function xsdTryParseDate(Chars, Last: xmlCharPtr; out Year, Month, Day: Longword; Timezone: PTimezone; BC: PBoolean): Boolean;
 var
   P: PChar;
@@ -873,42 +1002,43 @@ begin
 end;
 
 function xsdTryParseDecimal(Chars, Last: xmlCharPtr; out Value: Extended): Boolean;
+var
+  P: PChar;
+  L: PChar absolute Last;
 begin
-  Result := Assigned(Chars) and TryStrToFloat(__strpas(Chars, Last), Value);
-  {$warning slow parser!}
+  P := PChar(Chars);
+  if Assigned(Last) then
+    Result := Assigned(P) and __parseFloat(P, L, Value) and (P = L+1)
+  else
+    Result := Assigned(P) and __parseFloat(P, IGNORE_LAST, Value) and (P^ = #0);
 end;
 
 function xsdTryParseDouble(Chars, Last: xmlCharPtr; out Value: Double): Boolean;
+var
+  P: PChar;
+  L: PChar absolute Last;
+  Tmp: Extended;
 begin
-  Result := Assigned(Chars) and TryStrToFloat(__strpas(Chars, Last), Value);
+  P := PChar(Chars);
+  if Assigned(Last) then
+    Result := Assigned(P) and __parseFloat(P, L, Tmp) and (P = L+1)
+  else
+    Result := Assigned(P) and __parseFloat(P, IGNORE_LAST, Tmp) and (P^ = #0);
+  Value := Tmp;
 end;
 
 function xsdTryParseFloat(Chars, Last: xmlCharPtr; out Value: Single): Boolean;
-begin
-  Result := Assigned(Chars) and TryStrToFloat(__strpas(Chars, Last), Value);
-end;
-
-function __parseInteger(var P: PChar; const L: PChar; out Value: Int64): Boolean;
 var
-  N: Boolean;
+  P: PChar;
+  L: PChar absolute Last;
+  Tmp: Extended;
 begin
-  Value := 0;
-
-  { allow '-' }
-  N := (P <= L) and (P^ = '-');
-  if N then
-    Inc(P);
-
-  { read Integer }
-  while (P <= L) and (P^ in ['0'..'9']) do
-  begin
-    Value := 10*Value + Ord(P^) - Ord('0');
-    Inc(P);
-  end;
-  if N then
-    Value := -Value;
-
-  Result := True;
+  P := PChar(Chars);
+  if Assigned(Last) then
+    Result := Assigned(P) and __parseFloat(P, L, Tmp) and (P = L+1)
+  else
+    Result := Assigned(P) and __parseFloat(P, IGNORE_LAST, Tmp) and (P^ = #0);
+  Value := Tmp;
 end;
 
 function xsdTryParseInteger(Chars, Last: xmlCharPtr; out Value: Int64): Boolean;
@@ -923,20 +1053,6 @@ begin
     Result := Assigned(P) and __parseInteger(P, IGNORE_LAST, Value) and (P^ = #0);
 end;
 
-function __parseNonNegativeInteger(var P: PChar; const L: PChar; out Value: QWord): Boolean;
-begin
-  Value := 0;
-
-  { read Integer }
-  while (P <= L) and (P^ in ['0'..'9']) do
-  begin
-    Value := 10*Value + Ord(P^) - Ord('0');
-    Inc(P);
-  end;
-
-  Result := True;
-end;
-
 function xsdTryParseNonNegativeInteger(Chars, Last: xmlCharPtr; out Value: QWord): Boolean;
 var
   P: PChar;