Liukkaat kadut ale

Liukkaat kadut Apple Watch -sovellus on Black Friday -alessa 24.-27.11. hintaan 0€.

Kyllä, alennus on kokonaista 100%! Säästät jopa noin euron!

Huomaa että sovellus toimii vain Apple Watchissa ja seuraavissa kaupungeissa: Helsinki, Jyväskylä, Kuopio, Lahti ja Oulu. Liukkausvaroitukset tulevat kyseisten kaupunkien katujen kunnossapidosta vastaavilta. Sovellus toimii suomeksi, englanniksi ja ruotsiksi.

Slippery Cities Apple Watch app is on Black Friday sale from Nov 24th until Nov 27th with a price of 0€! Slippery Cities provides alerts of slippery weather for pedestrians in the following cities: Helsinki, Jyväskylä, Kuopio, Lahti and Oulu. The alerts are provided to your Apple Watch app by the service when the maintenance personnell of a city issues a slippery weather alert.

Liukkaat kadut App Storessa.

Write once, run everywhere

Is this Java code “write once, run everywhere”?

The checkFileHash method will calculate a hash for the file and check if the correctHash matches with the calculated hash. If the hashes match, the file is identical to what was expected.

boolean checkFileHash(String fileName, String correctHash) {
...
   File file = new File(fileName);
   MessageDigest md = MessageDigest.getInstance("SHA");
   FileInputStream fis = new FileInputStream(file);
   byte[] dataBytes = new byte[1024];
   
   int nread = 0;
   while ((nread = fis.read(dataBytes)) != -1) {
      md.update(dataBytes, 0, nread);
   }
   byte[] mdbytes = md.digest();
   StringBuilder sb = new StringBuilder();
   for (int i = 0; i < mdbytes.length; i++) {
      sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
   }
   fis.close();
   System.out.println("\nHash is " + sb.toString());
   return sb.toString().equals(correctHash);

Well this does compile, run and produce a file hash, compare it against the correct one and returns the result.

If the correctHash was calculated earlier on a same OS, hashes will even match. But if the corrrectHash was calculated in a different OS with a different default character encoding, the hashes do not match.

You need to explicitly specify that UTF-8 encoding is used when reading the file — which also should be saved UTF-8 encoded. And when calculating the expected correctHash the UTF-8 encoding should also be used. And when the hash for the file is calculated when file is inspected in this method:

boolean checkFileHash(String fileName, String correctHash) {
...
   // Use SHA for hashing, does not need to be secure.
   MessageDigest md = MessageDigest.getInstance("SHA");
   // Use buffered reader since we need to read explicitly using UTF-8.
   BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8"));

   // Read the lines from the line to a String.
   String line = null;
   StringBuilder sb = new StringBuilder();
   while ((line = br.readLine()) != null) {
      sb.append(line);
   }
   br.close();
   // Calculate the SHA digest (hash) from the string
   byte [] mdbytes = md.digest(sb.toString().getBytes("UTF-8"));

   // Convert the hash into a String.
   StringBuilder hsb = new StringBuilder();
   for (int i = 0; i < mdbytes.length; i++) {
      hsb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
   }
   String calculatedHash = hsb.toString();
   System.out.println("\nHash is " + calculatedHash.toString());
   // Check if the hash matches with the expected correct one.
   boolean matches = calculatedHash.equals(correctHash);
   if (!matches) {
      System.out.println("Correct has is: " + correctHash);
   }
   return matches;

Using a platform independent programming language does not guarantee platform independent code.

Obviously UTF-8 specifically is not required, but using a same encoding everywhere.

Once I used (on a macOS) a Java app with file open dialog, that was hardcoded to show directory C:\ by default. Sooooo platform independent…

Running Windows on Monterey in VirtualBox

Just a note to myself: if the Windows 10 on macOS Monterey in VirtualBox does not launch, do:

sudo kmutil load -p '/Library/Application Support/VirtualBox/VBoxDrv.kext'

And it should run. At least until the next time. Maybe someone somewhere fixes this sometimes.