javasqlitecodenameone

How can Bytes Array be handled successfully in iOS using Codename One


I am working on a app that uses SQLite. It encrypts and decrypts SQLite database using FilesCipher class in this answer

The app also saves images as byte[] in SQLite database. Images column has BLOB data type.

All these works as expected in Simulator & Android devices but NONE of these works in iOS device. I built these apps using build server.

When I use SQLite database WITHOUT encrypting it using FilesCipher class above, images are saved as expected in Simulator & Android but they are NOT saved in iOS device.

When I use SQLite database which is encrypted using FilesCipher class above, I can successfully decrypt and read records in database in Simulator & Android but in iOS it throws the following error ONLY.

java.io.IOException: SQL error in step.  Code: 10

I catched this error and stacktrace using the following code

    try {      



    } catch (Exception e) {
       Log.p("Error " + e + "\n" + getErrorInfo(e));
       //save this error log to a shareable text file
    }

    public String getErrorInfo(Exception error) {
        StringBuilder sbError = new StringBuilder();
        StackTraceElement[] errorArr = error.getStackTrace();
        for (StackTraceElement value : errorArr) {
            sbError.append("at ").append(value).append("\n");
        }
        return sbError.toString();
    }

I created images table with the following query

CREATE TABLE IF NOT EXISTS pictures ( id INTEGER  PRIMARY KEY AUTOINCREMENT, image BLOB)

Then inserted image with the following code

EncodedImage encodedImage = EncodedImage.create(image);
byte[] imageData = encodedImage.getImageData();
String query = "INSERT INTO pictures (image) VALUES (?)";
db.execute(query, imageData);

No error is thrown when inserting in iOS.

Note: FilesCipher encryptes & decrypts bytes[] and images are saved as bytes[]. That is, bytes[] is used in both cases.

How can both cases work in iOS as they are working in Simulator & Android?


Solution

  • Main database file encrypted using FilesCipher class above can't be read or written into until it's decrypted first.

    I was decrypting and writing decrypted bytes[] to the same main database file, execute queries in 1 request then after the request is successful or not, using } finally {} block I encrypt the main database file to keep it encrypted.This idea of encrypting & decrypting the same file works in Simulator & Android but fails in iOS.

    Seems there might be a problem in iOS when decrypting, reading & encrypting the same file.

    I did the following for this to work in all platforms including iOS.

    1. Decrypt main database which returns a decrypted byte[]

    2. Create a temp database and write this decrypted byte[] into it.

    3. Close main database to avoid GC warnings in iOS

    4. Set this temp database as the database to use

    5. Delete main database file

    6. Execute requested query or queries like save records in temp database

    7. Encrypt this temp database which returns encrypted byte[]

    8. Create main database file then write this encrypted byte[] to this newly created main database.

    9. Close the temp database to avoid GC warnings in iOS

    10. Set this new main database as the database to use.

    11. Delete the temp database file.

    Repeat these steps for every request.

    To enhance performance, if a class or a fuction is executing multiple different queries, the temp database should be reused until all queries have been executed then finally go to steps 7, 8, 9, 10 & 11