Skip to content

Commit

Permalink
feat(files): read & write using js buffers (#10093)
Browse files Browse the repository at this point in the history
  • Loading branch information
triniwiz committed Mar 17, 2023
1 parent 89fc249 commit 0173769
Show file tree
Hide file tree
Showing 7 changed files with 456 additions and 17 deletions.
165 changes: 165 additions & 0 deletions packages/core/file-system/file-system-access.android.ts
Expand Up @@ -254,6 +254,44 @@ export class FileSystemAccess implements IFileSystemAccess {
return this.getLogicalRootPath() + '/app';
}

public readBuffer = this.readBufferSync.bind(this);

public readBufferAsync(path: string): Promise<ArrayBuffer> {
return new Promise<ArrayBuffer>((resolve, reject) => {
try {
org.nativescript.widgets.Async.File.readBuffer(
path,
new org.nativescript.widgets.Async.CompleteCallback({
onComplete: (result: java.nio.ByteBuffer) => {
resolve((ArrayBuffer as any).from(result));
},
onError: (err) => {
reject(new Error(err));
},
}),
null
);
} catch (ex) {
reject(ex);
}
});
}

public readBufferSync(path: string, onError?: (error: any) => any) {
try {
const javaFile = new java.io.File(path);
const stream = new java.io.FileInputStream(javaFile);
const channel = stream.getChannel();
const buffer = new ArrayBuffer(javaFile.length());
channel.read(buffer as any);
return buffer;
} catch (exception) {
if (onError) {
onError(exception);
}
}
}

public read = this.readSync.bind(this);

public readAsync(path: string): Promise<number[]> {
Expand Down Expand Up @@ -293,6 +331,52 @@ export class FileSystemAccess implements IFileSystemAccess {
}
}

static getBuffer(buffer: ArrayBuffer | Uint8Array | Uint8ClampedArray): any {
if (buffer instanceof ArrayBuffer) {
return (buffer as any).nativeObject || buffer;
} else {
return (buffer?.buffer as any)?.nativeObject || buffer;
}
}

public writeBuffer = this.writeBufferSync.bind(this);

public writeBufferAsync(path: string, buffer: ArrayBuffer | Uint8Array | Uint8ClampedArray): Promise<void> {
return new Promise<void>((resolve, reject) => {
try {
org.nativescript.widgets.Async.File.writeBuffer(
path,
FileSystemAccess.getBuffer(buffer),
new org.nativescript.widgets.Async.CompleteCallback({
onComplete: () => {
resolve();
},
onError: (err) => {
reject(new Error(err));
},
}),
null
);
} catch (ex) {
reject(ex);
}
});
}

public writeBufferSync(path: string, buffer: ArrayBuffer | Uint8Array | Uint8ClampedArray, onError?: (error: any) => any) {
try {
const javaFile = new java.io.File(path);
const stream = new java.io.FileOutputStream(javaFile);
const channel = stream.getChannel();
channel.write(FileSystemAccess.getBuffer(buffer));
stream.close();
} catch (exception) {
if (onError) {
onError(exception);
}
}
}

public write = this.writeSync.bind(this);

public writeAsync(path: string, bytes: androidNative.Array<number>): Promise<void> {
Expand Down Expand Up @@ -757,6 +841,7 @@ export class FileSystemAccess29 extends FileSystemAccess {
getCurrentAppPath(): string {
return super.getCurrentAppPath();
}

public readText = this.readTextSync.bind(this);

readTextAsync(path: string, encoding?: any): Promise<string> {
Expand Down Expand Up @@ -795,6 +880,47 @@ export class FileSystemAccess29 extends FileSystemAccess {
}
}

readBuffer = this.readBufferSync.bind(this);

readBufferAsync(path: string): Promise<any> {
if (isContentUri(path)) {
return new Promise((resolve, reject) => {
getOrSetHelper(path).readBuffer(
applicationContext,
new org.nativescript.widgets.FileHelper.Callback({
onSuccess(result) {
resolve(result);
},
onError(error) {
reject(error);
},
})
);
});
}
return super.readBufferAsync(path);
}

readBufferSync(path: string, onError?: (error: any) => any) {
if (isContentUri(path)) {
let callback = null;
if (typeof onError === 'function') {
callback = new org.nativescript.widgets.FileHelper.Callback({
onSuccess(result) {},
onError(error) {
onError(error);
},
});
}
const ret = getOrSetHelper(path).readBufferSync(applicationContext, callback);
if (ret) {
return null;
}
return (ArrayBuffer as any).from(ret);
}
return super.readBufferSync(path, onError);
}

read = this.readSync.bind(this);

readAsync(path: string): Promise<any> {
Expand Down Expand Up @@ -872,6 +998,45 @@ export class FileSystemAccess29 extends FileSystemAccess {
}
}

writeBuffer = this.writeBufferSync.bind(this);

writeBufferAsync(path: string, content: any): Promise<void> {
if (isContentUri(path)) {
return new Promise<void>((resolve, reject) => {
getOrSetHelper(path).writeBuffer(
applicationContext,
FileSystemAccess.getBuffer(content),
new org.nativescript.widgets.FileHelper.Callback({
onSuccess(result) {
resolve();
},
onError(error) {
reject(error);
},
})
);
});
}
return super.writeAsync(path, content);
}

writeBufferSync(path: string, content: any, onError?: (error: any) => any) {
if (isContentUri(path)) {
let callback = null;
if (typeof onError === 'function') {
callback = new org.nativescript.widgets.FileHelper.Callback({
onSuccess(result) {},
onError(error) {
onError(error);
},
});
}
getOrSetHelper(path).writeSync(applicationContext, FileSystemAccess.getBuffer(content), callback);
} else {
super.writeSync(path, content, onError);
}
}

write = this.writeSync.bind(this);

writeAsync(path: string, content: any): Promise<void> {
Expand Down
12 changes: 12 additions & 0 deletions packages/core/file-system/file-system-access.d.ts
Expand Up @@ -298,6 +298,12 @@ export class FileSystemAccess implements IFileSystemAccess {

readTextSync(path: string, onError?: (error: any) => any, encoding?: any): string;

readBuffer(path: string, onError?: (error: any) => any): ArrayBuffer;

readBufferAsync(path: string): Promise<ArrayBuffer>;

readBufferSync(path: string, onError?: (error: any) => any): ArrayBuffer;

read(path: string, onError?: (error: any) => any): any;

readAsync(path: string): Promise<any>;
Expand All @@ -310,6 +316,12 @@ export class FileSystemAccess implements IFileSystemAccess {

writeTextSync(path: string, content: string, onError?: (error: any) => any, encoding?: any);

writeBuffer(path: string, content: ArrayBuffer | Uint8Array | Uint8ClampedArray, onError?: (error: any) => any);

writeBufferAsync(path: string, content: ArrayBuffer | Uint8Array | Uint8ClampedArray): Promise<void>;

writeBufferSync(path: string, content: ArrayBuffer | Uint8Array | Uint8ClampedArray, onError?: (error: any) => any);

write(path: string, content: any, onError?: (error: any) => any);

writeAsync(path: string, content: any): Promise<void>;
Expand Down
58 changes: 58 additions & 0 deletions packages/core/file-system/file-system-access.ios.ts
Expand Up @@ -294,6 +294,30 @@ export class FileSystemAccess {
}
}

public readBuffer = this.readBufferSync.bind(this);

public readBufferAsync(path: string): Promise<ArrayBuffer> {
return new Promise<ArrayBuffer>((resolve, reject) => {
try {
(NSData as any).dataWithContentsOfFileCompletion(path, (data) => {
resolve(interop.bufferFromData(data));
});
} catch (ex) {
reject(new Error("Failed to read file at path '" + path + "': " + ex));
}
});
}

public readBufferSync(path: string, onError?: (error: any) => any): ArrayBuffer {
try {
return interop.bufferFromData(NSData.dataWithContentsOfFile(path));
} catch (ex) {
if (onError) {
onError(new Error("Failed to read file at path '" + path + "': " + ex));
}
}
}

public read = this.readSync.bind(this);

public readAsync(path: string): Promise<NSData> {
Expand Down Expand Up @@ -352,6 +376,40 @@ export class FileSystemAccess {
}
}

static getBuffer(buffer: ArrayBuffer | Uint8Array | Uint8ClampedArray): NSData {
if (buffer instanceof ArrayBuffer) {
return NSData.dataWithData(buffer as any);
} else {
const buf = NSData.dataWithData(buffer?.buffer as any);
const len = buffer.byteLength;
return NSData.dataWithBytesNoCopyLength((buf.bytes as interop.Pointer).add(buffer?.byteOffset ?? 0), len);
}
}

public writeBuffer = this.writeBufferSync.bind(this);

public writeBufferAsync(path: string, content: ArrayBuffer | Uint8Array | Uint8ClampedArray): Promise<void> {
return new Promise<void>((resolve, reject) => {
try {
FileSystemAccess.getBuffer(content).writeToFileAtomicallyCompletion(path, true, () => {
resolve();
});
} catch (ex) {
reject(new Error("Failed to write file at path '" + path + "': " + ex));
}
});
}

public writeBufferSync(path: string, content: ArrayBuffer | Uint8Array | Uint8ClampedArray, onError?: (error: any) => any) {
try {
FileSystemAccess.getBuffer(content).writeToFileAtomically(path, true);
} catch (ex) {
if (onError) {
onError(new Error("Failed to write to file '" + path + "': " + ex));
}
}
}

public write = this.writeSync.bind(this);

public writeAsync(path: string, content: NSData): Promise<void> {
Expand Down
Binary file modified packages/core/platforms/android/widgets-release.aar
Binary file not shown.
Expand Up @@ -31,8 +31,10 @@
export module File {
export function readText(path: string, encoding: string, callback: CompleteCallback, context: any);
export function read(path: string, callback: CompleteCallback, context: any);
export function readBuffer(param0: string, param1: org.nativescript.widgets.Async.CompleteCallback, param2: any): void;
export function writeText(path: string, content: string, encoding: string, callback: CompleteCallback, context: any);
export function write(path: string, content: androidNative.Array<number>, callback: CompleteCallback, context: any);
export function writeBuffer(param0: string, param1: java.nio.ByteBuffer, param2: org.nativescript.widgets.Async.CompleteCallback, param3: any): void;
}

export module Http {
Expand Down Expand Up @@ -641,27 +643,31 @@ declare module org {
export class FileHelper {
public static class: java.lang.Class<org.nativescript.widgets.FileHelper>;
public readText(param0: globalAndroid.content.Context, param1: string, param2: org.nativescript.widgets.FileHelper.Callback): void;
public writeSync(param0: globalAndroid.content.Context, param1: androidNative.Array<number>, param2: org.nativescript.widgets.FileHelper.Callback): void;
public static fromString(param1: globalAndroid.content.Context, param0: string): org.nativescript.widgets.FileHelper;
public writeText(param0: globalAndroid.content.Context, param1: string, param2: string, param3: org.nativescript.widgets.FileHelper.Callback): void;
public writeBufferSync(param0: globalAndroid.content.Context, param1: java.nio.ByteBuffer, param2: org.nativescript.widgets.FileHelper.Callback): void;
public writeTextSync(param0: globalAndroid.content.Context, param1: string, param2: string, param3: org.nativescript.widgets.FileHelper.Callback): void;
public copyToFileSync(param0: globalAndroid.content.Context, param1: java.io.File, param2: org.nativescript.widgets.FileHelper.Callback): boolean;
public getName(): string;
public read(param0: globalAndroid.content.Context, param1: org.nativescript.widgets.FileHelper.Callback): void;
public copyToFile(param0: globalAndroid.content.Context, param1: java.io.File, param2: org.nativescript.widgets.FileHelper.Callback): void;
public static fromUri(param0: globalAndroid.content.Context, param1: globalAndroid.net.Uri): org.nativescript.widgets.FileHelper;
public renameSync(param0: globalAndroid.content.Context, param1: string, param2: org.nativescript.widgets.FileHelper.Callback): void;
public readSync(param0: globalAndroid.content.Context, param1: org.nativescript.widgets.FileHelper.Callback): androidNative.Array<number>;
public write(param0: globalAndroid.content.Context, param1: androidNative.Array<number>, param2: org.nativescript.widgets.FileHelper.Callback): void;
public static fromString(param0: globalAndroid.content.Context, param1: string): org.nativescript.widgets.FileHelper;
public getSize(): number;
public getMime(): string;
public readTextSync(param0: globalAndroid.content.Context, param1: string, param2: org.nativescript.widgets.FileHelper.Callback): string;
public static exists(param0: globalAndroid.content.Context, param1: globalAndroid.net.Uri): boolean;
public delete(param0: globalAndroid.content.Context): boolean;
public static exists(param0: globalAndroid.content.Context, param1: string): boolean;
public static exists(param0: globalAndroid.content.Context, param1: globalAndroid.net.Uri): boolean;
public getExtension(): string;
public getLastModified(): number;
public renameSync(param0: globalAndroid.content.Context, param1: string, param2: org.nativescript.widgets.FileHelper.Callback): string;
public rename(param0: globalAndroid.content.Context, param1: string, param2: org.nativescript.widgets.FileHelper.Callback): string;
public writeSync(param0: globalAndroid.content.Context, param1: androidNative.Array<number>, param2: org.nativescript.widgets.FileHelper.Callback): void;
public writeText(param0: globalAndroid.content.Context, param1: string, param2: string, param3: org.nativescript.widgets.FileHelper.Callback): void;
public readBuffer(param0: globalAndroid.content.Context, param1: org.nativescript.widgets.FileHelper.Callback): void;
public getName(): string;
public rename(param0: globalAndroid.content.Context, param1: string, param2: org.nativescript.widgets.FileHelper.Callback): void;
public writeBuffer(param0: globalAndroid.content.Context, param1: java.nio.ByteBuffer, param2: org.nativescript.widgets.FileHelper.Callback): void;
public copyToFile(param0: globalAndroid.content.Context, param1: java.io.File, param2: org.nativescript.widgets.FileHelper.Callback): void;
public readBufferSync(param0: globalAndroid.content.Context, param1: org.nativescript.widgets.FileHelper.Callback): java.nio.ByteBuffer;
public write(param0: globalAndroid.content.Context, param1: androidNative.Array<number>, param2: org.nativescript.widgets.FileHelper.Callback): void;
public getExtension(): string;
public readTextSync(param0: globalAndroid.content.Context, param1: string, param2: org.nativescript.widgets.FileHelper.Callback): string;
public static fromUri(param0: globalAndroid.content.Context, param1: globalAndroid.net.Uri): org.nativescript.widgets.FileHelper;
public static exists(param0: globalAndroid.content.Context, param1: string): boolean;
public getLastModified(): number;
}
export module FileHelper {
export class Callback {
Expand Down

0 comments on commit 0173769

Please sign in to comment.