// // This function include is meant to be used as an inner function! // // It requires the following variable declared in the outer scope: // readBuffer: RGMReadLineBuffer; // function ReadNextLine(const ASrcStream: ISequentialStream; const ACharKind: TGMCharKind; var ALine: TGMString; var ALineEnd: EGMLineEndKind; const ACaller: TObject): Boolean; const cLineEndLF: array [Boolean] of EGMLineEndKind = (lekLF, leLFCR); cLineEndCR: array [Boolean] of EGMLineEndKind = (lekCR, lekCRLF); //var byteLine: RawByteString; unicodeLine: TGMString; readMore: Boolean; function ReadByteChar(var ACh: AnsiChar): Boolean; inline; begin if readBuffer.byteBufChPos > readBuffer.bufByteCount then begin GMHrCheckObj(ASrcStream.Read(PAnsiChar(readBuffer.byteBuffer), Length(readBuffer.byteBuffer), @readBuffer.bufByteCount), ACaller, {$I %CurrentRoutine%}); readBuffer.byteBufChPos := 1; end; Result := readBuffer.byteBufChPos <= readBuffer.bufByteCount; if Result then begin ACh := readBuffer.byteBuffer[readBuffer.byteBufChPos]; Inc(readBuffer.byteBufChPos, SizeOf(AnsiChar)); end; end; //function ReadUnicodeChar(var ACh: UnicodeChar): Boolean; inline; //var byteCh1, byteCh2: AnsiChar; //begin // Result := ReadByteChar(byteCh1) and ReadByteChar(byteCh2); // if Result then Word(ACh) := Ord(byteCh2) shl 8 + Ord(byteCh1); //end; function ReadUnicodeChar(var ACh: UnicodeChar): Boolean; inline; begin if readBuffer.byteBufChPos > readBuffer.bufByteCount then begin GMHrCheckObj(ASrcStream.Read(PAnsiChar(readBuffer.byteBuffer), Length(readBuffer.byteBuffer), @readBuffer.bufByteCount), ACaller, {$I %CurrentRoutine%}); readBuffer.byteBufChPos := 1; end; Result := readBuffer.byteBufChPos <= readBuffer.bufByteCount-1; // <- SizeOf(UnicodeChar) if Result then begin ACh := PUnicodeChar(@readBuffer.byteBuffer[readBuffer.byteBufChPos])^; Inc(readBuffer.byteBufChPos, SizeOf(UnicodeChar)); end; end; function ReadByteLine: RawByteString; var ch, nextCh: AnsiChar; // byteBufRes: RGMGenericStringBuilder<RawByteString>; begin //byteBufRes.Len := 0; Result := ''; While ReadByteChar(ch) do begin case ch of #10: begin if not ReadByteChar(nextCh) then begin ALineEnd := cLineEndLF[false]; end else begin ALineEnd := cLineEndLF[nextCh = #13]; if nextCh <> #13 then Dec(readBuffer.byteBufChPos, SizeOf(AnsiChar)); // <- put last char back end; Break; // <- Breaks the loop not the case statement end; #13: begin if not ReadByteChar(nextCh) then begin ALineEnd := cLineEndCR[false]; end else begin ALineEnd := cLineEndCR[nextCh = #10]; if nextCh <> #10 then Dec(readBuffer.byteBufChPos, SizeOf(AnsiChar)); // <- put last char back end; Break; // <- Breaks the loop not the case statement end; //else byteBufRes += ch; else Result += ch; // <- Using RGMStringBuilder<RawByteString> here is slower! end; end; //Result := byteBufRes; end; function ReadUnicodeLine: UnicodeString; var ch, nextCh: UnicodeChar; begin Result := ''; While ReadUnicodeChar(ch) do begin case ch of #10: begin if not ReadUnicodeChar(nextCh) then begin ALineEnd := cLineEndLF[false]; end else begin ALineEnd := cLineEndLF[nextCh = #13]; if nextCh <> #13 then Dec(readBuffer.byteBufChPos, SizeOf(UnicodeChar)); // <- put last char back end; Break; // <- Breaks the loop not the case statement end; #13: begin if not ReadUnicodeChar(nextCh) then begin ALineEnd := cLineEndCR[false]; end else begin ALineEnd := cLineEndCR[nextCh = #10]; if nextCh <> #10 then Dec(readBuffer.byteBufChPos, SizeOf(UnicodeChar)); // <- put last char back end; Break; // <- Breaks the loop not the case statement end; else Result += ch; // <- Using RGMStringBuilder<UnicodeString> here is slower! end; end; end; begin if ASrcStream = nil then begin ALine := ''; ALineEnd := lekUnknown; Exit(false); end; case ACharKind of ckAnsi: ALine := ReadByteLine; ckUtf8: ALine := Utf8Decode(ReadByteLine); ckUtf16LE: ALine := ReadUnicodeLine; else begin ALine := ''; ALineEnd := lekUnknown; Exit(false); end; end; Result := (readBuffer.bufByteCount > 0) or (Length(ALine) > 0); end;