ionic-team / ionic-team/capacitor-filesystem

[Filesystem]: inconsistent file read/write action between android and web

Open
#35 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
6
Forks
15
Avg merge
14m
Merged PRs (30d)
1

Description

## Bug Report

### Plugin(s)

`@capacitor/filesystem`: `4.1.4`

### Capacitor Version
4x

### Platform(s)

- `android`
- `web`

### Bug

Looking through the source code I discovered inconsistent behaviors between `android` and `web`:

- `android` is working great:
- `readFile`:
+ when `encoding = undefined` it will forcibly read the file with `base64` https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java#L29
+ when `encoding = Encoding` it will be read as normal string https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java#L27
- `writeFIle`:
+ when `encoding = undefined` input `data` data is decoded and saved as `bin` https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java#L46
+ when `encoding = Encoding` Input data is accepted as a string `text/plain` https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/android/src/main/java/com/capacitorjs/plugins/filesystem/Filesystem.java#L38

- `android` has very obvious behaviors like `web` does not:
- `readFile`:
+ when `encoding = undefined` it is read and returns what is in `IndexedDB` https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/src/web.ts#L165
+ when `encoding = Encoding` it is read and returns what is in `IndexedDB` https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/src/web.ts#L165
- `writeFile`:
+ when `encoding = undefined` it is check is `base64` and save raw to `IndexedDB` https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/src/web.ts#L200
+ when `encoding = Encoding` it is check is `base64` and save raw to `IndexedDB` https://github.com/ionic-team/capacitor-plugins/blob/main/filesystem/src/web.ts#L200

the problem is that these actions lead to an unclear status on the `web`
I run on `web`:
```ts
await Filesystem.writeFile({
path: "test.txt",
directory: Directory.External,
data: "ASuZAADVfA==",
encoding: Encoding.UTF8
})

await Filesystem.writeFile({
path: "test.bin",
directory: Directory.External,
data: "ASuZAADVfA=="
})
```

`sha256('test.txt') === sha256('test.bin')` while they are obviously two completely different files `text.txt` contains a base64 string and `text.bin` contains a data represented by base64

this behavior becomes even more weird in `readFile` when I run this code:
```ts
await Filesystem.writeFile({
path: "test.txt",
directory: Directory.External,
data: "hello world",
encoding: Encoding.UTF8
})

const base64 = await Filesystem.readFile({
path: "test.txt",
directory: Directory.External,
}).then(res => res.data)

console.log(base64) // "hello world"
```

this result doesn't make sense because apparently `base64.encode('hello world')` is `aGVsbG8gd29ybGQ=`

### Solution
(here is my workaround)

#### Encode all to `base64` before saving to `IndexedDB`
This prevents a binary file with base64 of `x` from looking exactly like a text file containing utf8 of `x`

#### Make base64 explicit by saving files with `encoding = undefined` as `ArrayBuffer` or `Uint8Array`
Make base64 explicit by saving files with `encoding = undefined` as `ArrayBuffer` or `Uint8Array` into `IndexedDB` (this is allowed and a standard of `IndexedDB`)
then we will have an implementation that looks like this:
```ts
function writeFile(options: WriteFileOptions) {
if (options.encoding) {
// normal save
} else {
const data = base64ToUint8(options.data)
// normal save
}
}
function readFile(options: ReadFileOptions) {
if (options.encoding) {
// normal read
} else {
const data = ... // normal read

return uint8ToBase64(data)
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.