VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

This forum is meant for questions about the Visual FoxPro Language support in X#.

User avatar
Tom_B
Posts: 5
Joined: Tue Aug 20, 2019 9:00 am

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Tom_B »

Hi Chris,

the string content can be pictures, pdf, docs, whatever as long as they are send as mail. In such cases, I move the file content into a variable and then convert this variable into base64

Code: Select all

lcStream = FILETOSTR( GETFILE() )
lcMime = STRCONV( lcStream , 13 )
lcMime then becomes part of a JSON String and via xmlhttp-Post JSON is send to our Webservice that handles transmission and anything else.

Here is some sample code based on a commandbutton.tag property that holds the path and filename of the to be send file. 'lcDlePar' will be transmitted with xmlhttp.post contacting out own webservice:

Code: Select all

WITH Thisform.cmgAnhang

    FOR liLoop = 1 TO .ButtonCount
        lcStream = FILETOSTR( .Buttons( liLoop ).Tag )
        lcAttach = lcAttach + [{ "id" : ] + TRANSFORM( liLoop ) + [ , "name" : "] + JUSTFNAME( .Buttons( liLoop ).Tag ) +  [" , "file" : "] + STRCONV( lcStream , 13 ) + [" }]
        lcAttach = lcAttach + IIF( liLoop < .ButtonCount , [ ,] , [] )
    ENDFOR 

ENDWITH 

TEXT TO lcDlePar TEXTMERGE NOSHOW PRETEXT 1+2+3+8
    {
    "to" : "<<ALLTRIM( Thisform._To )>>" ,
    "from" : "<<ALLTRIM( Thisform._From )>>" ,
    "cc" : "<<ALLTRIM( Thisform._Cc )>>" ,
    "bcc" : "<<ALLTRIM( Thisform._Bcc )>>" ,
    "subject" : "<<ALLTRIM( Thisform._Subject )>>" ,
    "body" : "<<Thisform.Converter( Thisform._Body )>>" ,
    "attachments" : [ <<lcAttach>> ]
    }
ENDTEXT 
In case of HEX conversion this is a typical XML file where I use something like that with STRCONV(15). In this example xmls_gridprint contains a complete VFP cursor transformed into HEX. This is done with CURSORTOXML() and STRCONV():

Code: Select all

<?xml version = "1.0" encoding="Windows-1252" standalone="yes"?>
<VFPData>
	<xsd:schema id="VFPData" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
		<xsd:element name="VFPData" msdata:IsDataSet="true">
			<xsd:complexType>
				<xsd:choice maxOccurs="unbounded">
					<xsd:element name="crs114paramx" minOccurs="0" maxOccurs="unbounded">
						<xsd:complexType>
							<xsd:sequence>
								<xsd:element name="public_cueberschrift">
									<xsd:simpleType>
										<xsd:restriction base="xsd:string">
											<xsd:maxLength value="2147483647"></xsd:maxLength>
										</xsd:restriction>
									</xsd:simpleType>
								</xsd:element>
								<xsd:element name="xmls_gridprint">
									<xsd:simpleType>
										<xsd:restriction base="xsd:string">
											<xsd:maxLength value="2147483647"></xsd:maxLength>
										</xsd:restriction>
									</xsd:simpleType>
								</xsd:element>
								<xsd:element name="para_stream">
									<xsd:simpleType>
										<xsd:restriction base="xsd:string">
											<xsd:maxLength value="2147483647"></xsd:maxLength>
										</xsd:restriction>
									</xsd:simpleType>
								</xsd:element>
							</xsd:sequence>
						</xsd:complexType>
					</xsd:element>
				</xsd:choice>
				<xsd:anyAttribute namespace="http://www.w3.org/XML/1998/namespace" processContents="lax"></xsd:anyAttribute>
			</xsd:complexType>
		</xsd:element>
	</xsd:schema>
	<crs114paramx>
		<public_cueberschrift><![CDATA[Auftrag    Ladetag   Pst   NVE      A'Geber      KG eff   CBM      Ladeort      Entladeort]]></public_cueberschrift>
		<xmls_gridprint><![CDATA[3C3F786D6C2076657273696F6E203D2022312E302220656E636F64696E673D2257696E646F77732D3132353222207374616E64616C6F6E653D22796573223F3E3C564650446174613E3C7873643A736368656D612069643D22564650446174612220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A6D73646174613D2275726E3A736368656D61732D6D6963726F736F66742D636F6D3A786D6C2D6D7364617461223E3C7873643A656C656D656E74206E616D653D225646504461746122206D73646174613A4973446174615365743D2274727565223E3C7873643A636F6D706C6578547970653E3C7873643A63686F696365206D61784F63637572733D22756E626F756E646564223E3C7873643A656C656D656E74206E616D653D226372736472756772696422206D696E4F63637572733D223022206D61784F63637572733D22756E626F756E646564223E3C7873643A636F6D706C6578547970653E3C7873643A73657175656E63653E3C7873643A656C656D656E74206E616D653D227A65696C65223E3C7873643A73696D706C65547970653E3C7873643A7265737472696374696F6E20626173653D227873643A737472696E67223E3C7873643A6D61784C656E6774682076616C75653D2232313437343833363437223E3C2F7873643A6D61784C656E6774683E3C2F7873643A7265737472696374696F6E3E3C2F7873643A73696D706C65547970653E3C2F7873643A656C656D656E743E3C2F7873643A73657175656E63653E3C2F7873643A636F6D706C6578547970653E3C2F7873643A656C656D656E743E3C2F7873643A63686F6963653E3C7873643A616E79417474726962757465206E616D6573706163653D22687474703A2F2F7777772E77332E6F72672F584D4C2F313939382F6E616D657370616365222070726F63657373436F6E74656E74733D226C6178223E3C2F7873643A616E794174747269627574653E3C2F7873643A636F6D706C6578547970653E3C2F7873643A656C656D656E743E3C2F7873643A736368656D613E3C637273647275677269643E3C7A65696C653E3C215B43444154415B207C203230303030313730207C2032302E30372E32207C20202031207C20202020202030207C204A616E6E6973204A6163207C20202031303030207C202020302C3030207C204A616E6E6973204A6163207C20616374697665206C6F675D5D3E3C2F7A65696C653E3C2F637273647275677269643E3C637273647275677269643E3C7A65696C653E3C215B43444154415B207C203230303030313731207C2032302E30372E32207C20202031207C20202020202030207C204A616E6E6973204A6163207C20202031303030207C202020312C3037207C204A616E6E6973204A6163207C20616374697665206C6F675D5D3E3C2F7A65696C653E3C2F637273647275677269643E3C637273647275677269643E3C7A65696C653E3C215B43444154415B207C203230303030313732207C2032302E30372E32207C20202031207C20202020202031207C204A616E6E6973204A6163207C20202031303030207C202020302C3030207C204A616E6E6973204A6163207C20616374697665206C6F675D5D3E3C2F7A65696C653E3C2F637273647275677269643E3C2F564650446174613E]]></xmls_gridprint>
		<para_stream><![CDATA[2023503A3233202023553A6A6A202023543A436F6E736F6C652020234D3A33392020234F3A31202023563A4D616E64616E743D33393B417566747261673D3230303030313732202023413A31]]></para_stream>
	</crs114paramx>
</VFPData>
User avatar
Chris
Posts: 4725
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Chris »

Hi Tom,

For the reason I explained earlier, this will need to be adjusted in .Net. For binary data, instead of FILETOSTR(), we need to introduce something like FILETOBYTES(), which will load the file contents to a var that is suitable for holding binary data, instead of the string type which cannot do this. Same with the other conversion functions.

Here's a very quick implementation of such functions and how it would be used in VFP code:

Code: Select all

FUNCTION Start() AS INT
	LOCAL data,base64
	data := FILETOBYTES("c:testbitmap.bmp")
	base64 := BYTESCONV(data , 13)
	? base64
	RETURN 0
END FUNCTION

* following will be defined in the X# runtime
FUNCTION FILETOBYTES(cFileName AS STRING) AS BYTE[]
RETURN System.IO.File.ReadAllBytes(cFileName)

FUNCTION BYTESCONV(aData AS BYTE[], nType AS INT) AS STRING
LOCAL cRet := "" AS STRING
DO CASE
CASE nType == 13
	cRet := Convert.ToBase64String(aData)
END CASE
RETURN cRet
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am
Location: Portugal

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by atlopes »

Chris, the current X# implementation of STRTOFILE() and FILETOSTR() already support binary files.
User avatar
Chris
Posts: 4725
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Chris »

Hi Antonio,

It reads binary files, but needs to convert each byte read to an equivalent unicode value that is readable and is different to the original value. To explain what I mean, please see this sample, it creates a binary file 256 bytes long, with contents 0.1.2...255. Then it reads it back with FILETOSTR():

Code: Select all

FUNCTION Start() AS INT
LOCAL cFileName AS STRING
cFileName := "c:testbinary.dat"

* create a file with 256 bytes, from 0 to 255
LOCAL aBytes AS BYTE[]
aBytes := BYTE[]{256}
FOR LOCAL n := 1 AS INT UPTO 256
	aBytes[n] := (BYTE)(n -1)
NEXT
System.IO.File.WriteAllBytes(cFileName,aBytes)

* read it back
LOCAL cContents AS STRING
cContents := FILETOSTR(cFileName)
? cContents
FOR LOCAL n := 1 AS INT UPTO 256
	? "Char", n, ":", (INT)cContents[n-1]
NEXT
RETURN 0

See the values of each character in the returned string, in many cases this is different to the original one, because of the 8 bit->unicode conversion.

But maybe you are right and this is not really a problem, if you are careful to always convert back to ansi when manipulating this string, then you can assume it is "binary" and safely use it, save it back etc. At least when your strings use characters from only one codepage and do not mix for example German and Greek chars. Please let me think about this a bit more...
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am
Location: Portugal

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by atlopes »

Ok, Chris, I'll open a thread on STRCONV() once I have a basic working draft of its implementation.

Meanwhile, on the shoulders of your sample:

Code: Select all

FUNCTION Start() AS INT
LOCAL cFileName AS STRING
cFileName := "c:testbinary.dat"
cCopyFileName := "c:testcopy of binary.dat"

* create a file with 256 bytes, from 0 to 255
LOCAL aBytes AS BYTE[]
aBytes := BYTE[]{256}
FOR LOCAL n := 1 AS INT UPTO 256
	aBytes[n] := (BYTE)(n -1)
NEXT
System.IO.File.WriteAllBytes(cFileName,aBytes)

* read and write it back
LOCAL cContents AS STRING
cContents := FILETOSTR(cFileName)
STRTOFILE(cContents, cCopyFileName)
RETURN 0
produces a bit-by-bit copy of the original binary file.
User avatar
Chris
Posts: 4725
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Chris »

Hi Antonio,

Yes, it produces the same output, because the string was not manipulated at all since it was read and STRTOFILE() does the exact opposite unicode->ansi conversion. to what FILETOSTR() did. It's modifying the contents inside the buffer that could lead to problems.

Also this unicode<>ansi conversion will be different in systems with different system locales and I am not sure if it is guaranteed to be 1:1 in all cases even in the same system. This needs some further investigation...
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am
Location: Portugal

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by atlopes »

Chris
it produces the same output, because the string was not manipulated at all since it was read and STRTOFILE() does the exact opposite unicode->ansi conversion
Yes, I'm aware of that.
Also this unicode<>ansi conversion will be different in systems with different system locales and I am not sure if it is guaranteed to be 1:1 in all cases even in the same system. This needs some further investigation...
In VFP, STRCONV() is fully sensitive to locale (system's or explicitly set in its arguments). An X# implementation will have to consider that, also, and execute in the same manner.

Edited: ok, I realize better your point, here. I'll dig into this, also, but remember that the data is being treated as single-byte data in the 0-255 plane. I think all conversions Unicode-ANSI support full roundtrip ability at these codepoints.
User avatar
robert
Posts: 4388
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by robert »

Guys,

The message about the unmatched ">>" token is not a bug. It is a compiler warning, that you can suppress if you want.
I do not think we should remove the warning. It is far more likely I think that people will have an unmatched ">>" token by mistake then that they will use an output redirect like in this example.
You have 2 options here:
- use a different character and do a StrTran() afterwards
- disable the compiler warning with a pragma for the entity involved.

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
Post Reply