Jump to content

A.M. Hoornweg

Members
  • Content Count

    473
  • Joined

  • Last visited

  • Days Won

    9

Everything posted by A.M. Hoornweg

  1. Because the data is not strings. But the in-memory representation of a dynamic array is rather similar so the functionality should be straightforward to duplicate. And thanks to generics, it's probably possible to design the base class to be universal, IIRC a tbytes is just something like "tarray<byte>" (but I may be wrong here).
  2. Lookup "operator overloading". It should be possible to do something like newbytes:=something+somethingelse+'Hello world'; But adding text to tBytes or searching a text inside a tBytes would mean code page handling. You could consider defining a Binarystring type (type binarystring=type Ansistring (28591)) because that's least likely to get messed up.
  3. Strings should not be used for byte manipulation (which does not contradict an earlier post of mine, explaining how to get legacy code libraries working if they do this). Rather, write a new class or class helper that enhances tbytes and offers the functionality that makes strings so practical (insert, delete, append, concatenate, pos). Maybe even some new classes "tBytelist" and "tByteBuilder" as an analog to tStringlist and tStringbuilder.
  4. When I want to safely delete a component on an ancestor form, I do it outside of Delphi. I use a search tool (Agent Ransack) to find out if the component appears in any descendant forms. I simply search the folder for all *.dfm files which contain the text "inherited mycomponentname". Then I simply drag &drop the resulting list of file names onto an empty Notepad++ window and perform the deletion manually. When this is done, it is safe to delete the component on the ancestor form.
  5. A.M. Hoornweg

    Any Known Issues with ZCompressStream?

    Which brings us back to the solution I proposed originally. Ensure that the compressed data is valid (with another checksum) before trying to feed it to the decompressor.
  6. A.M. Hoornweg

    Any Known Issues with ZCompressStream?

    If the data can only be verified after expansion and the expansion algorithm crashes, then we still don't know if the data or the implementation is broken.
  7. A.M. Hoornweg

    Any Known Issues with ZCompressStream?

    If that were true, a non-matching checksum would mean a broken algorithm and not necessarily broken data. It would tell us exactly nothing.
  8. A.M. Hoornweg

    Any Known Issues with ZCompressStream?

    "contains a checksum value of the uncompressed data" This isn't foolproof because the decompressor can only verify that checksum after decompression. What if the data is corrupted in such a way that it causes the decompressor to crash (I quote OP: "endless loop") during decompression? One should also append a record containing the size and checksum of the compressed data at the end of the stream. That way one can check the integrity of the file before decompressing the data.
  9. A.M. Hoornweg

    Automatically killing a service when stuck

    I had situations where an ADO connection to MS SQL Server would just "lock up" whilst executing a SQL statement and the call never returned. No exception, no error, just a lockup. I suspect it had something to do with our IT department's scheduled backup job saving the SQL Server VM because it always happened around that time of night. Since lockups like that are out of the programmer's control, all I could do was design a workaround and it turned out that a watchdog thread worked brilliantly.
  10. A.M. Hoornweg

    "Simulating" a com port with data arriving

    VMWare workstation will let you do this. Just add two virtual serial ports to the VM, in the field "connection" specify "named pipe". Both COM ports must use the same name for the named pipe (just call it "serialportpipe") and one port must be configured to be "server", the other must be "client". That way, the two COM ports are crosswired. Now you can start 2 applications, connect them up to the two COM ports and let them talk to each other.
  11. A.M. Hoornweg

    Any Known Issues with ZCompressStream?

    I don't know if Zlib writes a checksum or not, maybe you should append it yourself at the end of the compressed stream. Then first verify that checksum before trying to decompress it.
  12. A.M. Hoornweg

    Automatically killing a service when stuck

    I do it slightly differently: - The main process launches a child process for the work. - The child process creates a mutex. The service application knows if the child process is still running by periodically checking the mutex. - The child process has a separate thread called tWatchdogThread. - The main thread must call "tWatchdogThread.Notify" regularly to prove it's still alive. - If that sign of life stays out for more than 10 seconds, the watchdog assumes the main thread has crashed and ends the process using TerminateProcess(). This mechanism has proved to be extremely reliable, I use it often.
  13. Hello all, when Delphi didn't know about unicode yet people would often stuff binary data into strings because strings were soooo practical and easy to manipulate. Yes that is and was bad practice and highly frowned upon, but as we all know it was done anyway and people got away with it because Delphi didn't care about code pages at the time so it just worked. It was even done in professional libraries. Code like that is very hard to port to newer Delphi versions which are unicode-enabled and codepage-aware and when you attempt a conversion, subtle errors may happen where you least expect it. If you still have precious old code libraries that do such things and which would be too costly or too complex to rewrite, you may consider trying this workaround as a quick & dirty fix: Type Binarystring= type Ansistring (437); The nice thing about code page 437 is that all 256 possible ansichar values map to valid unicode code points so you can safely assign these strings to Unicodestrings and back again without data loss and Delphi's built-in string functions won't break the binary data contained in these strings. So you just may me able to salvage some legacy code by declaring this new type and then replacing all "string" declarations in the code with "binarystring" and all (p)Char with (p)Ansichar. And yes, it's still bad practice... (The idea is originally from Raymond Chen: https://devblogs.microsoft.com/oldnewthing/20200831-00/?p=104142 )
  14. A.M. Hoornweg

    Workaround for binary data in strings ...

    For my own source code I switched to tBytes too, long ago. But I have several legacy third party libraries of companies that no longer exist and that are still very nice when used with Delphi 2007. So when I came across Raymond Chen's blog I had the idea to salvage these libraries without mutilating the existing source code too much. And I stated loudly and clearly that this is just a quick & dirty fix to get it done. As Remy Lebeau stated, assigning RawByteString <-> String may still do a codepage conversion. Ansistring(437) and Ansistring (28591) are safe.
  15. A.M. Hoornweg

    Workaround for binary data in strings ...

    The VCL was strictly Ansi. I needed visual unicode compatibility in the early noughties and was forced to switch to a third-party VCL (first TNT, then LMD Elpack).
  16. A.M. Hoornweg

    Workaround for binary data in strings ...

    Fair point. Moreover, the only tool in Delphi that could perform operations like copy/append/delete/insert/search on variable length data out of the box was "string". If all you have is a hammer, every problem looks like a nail. I remember that Windows NT (from the mid-1990s) was already unicode-enabled but Delphi didn't support that until version 2009. So all that time, a char and a byte were basically synonymous in Delphi.
  17. A.M. Hoornweg

    Workaround for binary data in strings ...

    I do, all the time. But this is about salvaging older (possibly third party) ansi code without a rewrite.
  18. A.M. Hoornweg

    Workaround for binary data in strings ...

    The documentation says that "Rawbytestring should only be used as a const or value type parameter or a return type from a function. It should never be passed by reference (passed by var), and should never be instantiated as a variable." I read that as "you may not declare variables of type "RawByteString" and do stuff with them". But if I define a Type Ansistring(437) and put binary data into it, the data is associated with a valid code page. A conversion to unicodestring will convert characters [#128..#255] to some different unicode code points, which is uninteresting, because a back-conversion to ansi codepage 437 will produce the original binary data again. So it is safe to use all normal unicode string functions as long as we remember to assign the final results back to an Ansistring(437).
  19. A.M. Hoornweg

    UCS4Strings

    Voted!
  20. Hello all, could it be that function UCS4StringToWideString misses the final character during the conversion? VAR s:UCS4String; W:String; begin s:=[220,98,101,114,109,228,223,105,103]; w:=UCS4StringToWideString(s); showmessage(w); end;
  21. A.M. Hoornweg

    UCS4StringToWideString broken?

    Most programmers ignore that UTF-16 is a variable-length encoding and treat it like UCS-2, falsely assuming that one widechar corresponds to one codepoint. While most of us probably don't handle exotic languages, this is the 21st century and sooner or later you'll stumble upon strings that contain Emoticons which just won't fit in one widechar ( https://en.wikipedia.org/wiki/Emoticons_(Unicode_block) . Delphi could use some better support for that, like iterators etc. Something like this: Function ReverseString (S:String):String; VAR c:UCS4Char; Begin Result:=''; FOR c in s do result:=c + result; End; And if you think this is far fetched, just look how elegantly Freepascal solves this, https://wiki.freepascal.org/for-in_loop#Traversing_UTF-8_strings .
  22. A.M. Hoornweg

    ExtractFileDrive bug

    I've just discovered that ExtractFileDrive misses a corner case on Windows and posted a QC about it. https://quality.embarcadero.com/browse/RSP-31109 I was experimenting with very long file and path names (see https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation) and stumbled upon a file name syntax which I hadn't seen before. It turned out that Delphi didn't know about it either. The syntax is \\?\UNC\server\share which is just another way of writing \\server\share. Delphi's ExtractFileDrive returns "\\?\UNC" on such a path which is meaningless.
  23. A.M. Hoornweg

    UCS4StringToWideString broken?

    OK, I'll post a QC then. Edit: https://quality.embarcadero.com/browse/RSP-31114
  24. A.M. Hoornweg

    ExtractFileDrive bug

    The word "drive" is a bit unlucky. What ExtractFileDrive() really does is to return the root of a volume, which can be either a drive letter or a file share. ExtractFileDrive ('\\server\share\folder\filename.ext") returns "\\server\share", which is perfectly OK. I can use the result as the root path for a folder structure without problems. ExtractFileDrive ('\\?\C:\folder\filename.ext") returns "\\?\C:" which is also perfectly OK. This result, too, can be used as the root path for a folder structure without problems. The only corner case that isn't handled correctly is "\\?\UNC\" which is needed for long network paths. I think it wouldn't hurt anyone to support that syntax as well.
  25. A.M. Hoornweg

    ExtractFileDrive bug

    I respectfully disagree. The prefix "\\?\" is a well-known method to tell Windows that a program is able to parse file names longer than MAX_PATH. It seems that the prefix \\?\UNC\ extends this ability to network paths. Otherwise I wouldn't bother with them. But in this specific case I needed to test if two paths referred to the same volume so I used ExtractFileDrive, which failed on this syntax.
×