Search code examples
character-encodingsmalltalksqueakmonticello

Squeak Monticello character-encoding


For a work project I am using headless Squeak on a (displayless, remote) Linuxserver and also using Squeak on a Windows developer-machine.

Code on the developer machine is managed using Monticello. I have to copy the mcz to the server using SFTP unfortunately (e.g. having a push-repository on the server is not possible for security reasons). The code is then merged by eg:

MczInstaller installFileNamed: 'name-b.18.mcz'.

Which generally works.

Unfortunately our code-base contains strings that contain Umlauts and other non-ascii characters. During the Monticello-reimport some of them get replaced with other characters and some get replaced with nothing.

I also tried e.g.

MczInstaller installStream: (FileStream readOnlyFileNamed: '...') binary

(note .mcz's are actually .zip's, so binary should be appropriate, i guess it is the default anyway)

Finding out how to make Monticello's transfer preserve the Squeak internal-encoding of non-ascii's is the main Goal of my question. Changing all the source code to only use ascii-strings is (at least in this codebase) much less desirable because manual labor is involved. If you are interested in why it is not a simple grep-replace in this case read this side note:

(Side note: (A simplified/special case) The codebase uses Seaside's #text: method to render strings that contain chars that have to be html-escaped. This works fine with our non-ascii's e.g. it converts ä into ä, if we were to grep-replace the literal ä's by ä explicitly, then we would have to use the #html: method instead (else double-escape), however that would then require that we replace all other characters that have to be html-escaped as well (e.g. &), but then again the source-code itself contains such characters. And there are other cases, like some #text:'s that take third-party strings, they may not be replaced by #html's...)


Solution

  • Squeak does use unicode (ISO 10646) internally for encoding characters in a String.
    It might use extension like CP1252 for characters in range 16r80 to: 16r9F, but I'm not really sure anymore.

    The characters codes are written as is on the stream source.st, and these codes are made of a single byte for a ByteString when all characters are <= 16rFF. In this case, the file should look like encoded in ISO-8859-L1 or CP1252.

    If ever you have character codes > 16rFF, then a WideString is used in Squeak. Once again the codes are written as is on the stream source.st, but this time these are 32 bits codes (written in big-endian order). Technically, the encoding is thus UTF-32BE.

    Now what does MczInstaller does? It uses the snapshot/source.st file, and uses setConverterForCode for reading this file, which is either UTF-8 or MacRoman... So non ASCII characters might get changed, and this is even worse in case of WideString which will be re-interpreted as ByteString.

    MC itself doesn't use the snapshot/source.st member in the archive.
    It rather uses the snapshot.bin (see code in MCMczReader, MCMczWriter).
    This is a binary file whose format is governed by DataStream.

    The snippet that you should use is rather:

    MCMczReader loadVersionFile: 'YourPackage-b.18.mcz'