xtool/contrib/mORMot/SyNode/SyNodeReadWrite.pas

130 lines
4.3 KiB
ObjectPascal

unit SyNodeReadWrite;
interface
uses
SpiderMonkey, Classes, SynCommons;
// TODO - replace this implemenattion by buffers whed buffers become fully compartible with nodeJS
/// Used for create JS method for writing data to internal class buffer
// JS syntax: write(data: ArrayBuffer|String|Object, [encoding: "utf-8"|"ucs2"|"bin"|"base64"]'
// inmplementation must provide TTextWriter to write data to
function SMWrite_impl(cx: PJSContext; argc: uintN; vals: PjsvalVector; dest: TTextWriter): jsval; cdecl;
/// Used for create JS method for reading data from internal class buffer (aStr)
// JS syntax: read([encoding=utf-8: "utf-8"|"ucs2"|"bin"|"base64"])
// implementation must provide TTextWriter to write data to
function SMRead_impl(cx: PJSContext; argc: uintN; vals: PjsvalVector; const aStr: RawByteString): jsval; cdecl;
implementation
{$ifdef MSWINDOWS}
uses
Windows; // CP_UTF8
{$endif}
function SMRead_impl(cx: PJSContext; argc: uintN; vals: PjsvalVector; const aStr: RawByteString): jsval; cdecl;
var
encoding: RawUTF8;
len: Integer;
bufObj: PJSObject;
bufData: pointer;
decodedStr: RawByteString;
begin
if (argc = 0) or ((argc=1) and vals[0].isVoid) then
encoding := 'utf-8'
else
encoding := LowerCase(vals[0].asJSString.ToUTF8(cx));
if encoding = 'utf-8' then begin
Result := cx.NewJSString(Pointer(aStr), length(aStr), CP_UTF8).ToJSVal
end else if encoding = 'Windows-1251' then begin
Result := cx.NewJSString(Pointer(aStr), length(aStr), 1251).ToJSVal
end else if encoding = 'ucs2' then begin
Result := cx.NewJSString(aStr).ToJSVal
end else if encoding = 'bin2base64' then begin
decodedStr := BinToBase64(aStr);
Result := cx.NewJSString(decodedStr).ToJSVal;
end else if (encoding = 'bin') or (encoding = 'base64') then begin
if encoding = 'base64' then
decodedStr := Base64ToBin(aStr)
else
decodedStr := aStr;
len := length(decodedStr);
bufObj := cx.NewArrayBuffer(len);
bufData := bufObj.GetArrayBufferData;
Move(pointer(decodedStr)^, bufData^, len);
Result := bufObj.ToJSValue;
end else
raise ESMException.Create('Invalid encoding');
end;
function SMWrite_impl(cx: PJSContext; argc: uintN; vals: PjsvalVector; dest: TTextWriter): jsval; cdecl;
var
encoding: RawUTF8;
len: uint32;
isShared: boolean;
bufObj: PJSObject;
bufData: Puint8Vector;
tmp1: RawByteString;
tmp2: SynUnicode;
begin
if (argc < 1) or (argc>2) then
raise ESMException.Create('Usage: write(data: ArrayBuffer|String|Object, [encoding: "utf-8"|"ucs2"|"bin"|"base64"]');
encoding := '';
if argc=2 then begin
if (argc = 2) and (vals[1].isString) then
encoding := LowerCase(vals[1].asJSString.ToUTF8(cx));
end;
case cx.TypeOfValue(vals[0]) of
JSTYPE_STRING: begin
if (encoding = '') or (encoding = 'utf-8') or (encoding = 'utf8') then // default is utf-8
vals[0].asJSString.ToUTF8(cx, dest)
else if (encoding = 'ucs2') then begin
tmp2 := vals[0].asJSString.ToSynUnicode(cx);
dest.AddNoJSONEscapeW(pointer(tmp2), length(tmp2));
end else
raise ESMException.Create('invalid encoding');
end;
JSTYPE_NUMBER:
if vals[0].isInteger then
dest.Add(vals[0].asInteger)
else
dest.AddDouble(vals[0].asDouble);
JSTYPE_OBJECT: begin
bufObj := vals[0].asObject;
if bufObj=nil then begin
Result.asBoolean := true;
Exit;
end;
if bufObj.GetBufferDataAndLength(bufData, len) then begin
if encoding = 'base64' then begin
tmp1 := BinToBase64(PAnsiChar(bufData), len);
bufData := Puint8Vector(tmp1);
len := Length(tmp1);
encoding := 'bin';
end;
if (encoding = '') or (encoding = 'bin') then begin // default is bin
if len>0 then
dest.AddNoJSONEscape(pointer(bufData), len)
end else
raise ESMException.Create('invalid encoding');
end else begin
if (encoding = '') or (encoding = 'utf-8') or (encoding = 'utf8') then // default is utf-8
vals[0].AddJSON(cx, dest)
else
raise ESMException.Create('invalid encoding');
end;
end;
JSTYPE_VOID: begin end; // do nothing
else
raise ESMException.Create('invalid parameter type for Writer');
end;
result.asBoolean := True;
end;
end.