/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
// The Cangjie API is in Beta. For details on its capabilities and limitations, please refer to the README file.
package std.process
import std.io.*
/**
* ProcessOutputStream implement OutputStream & Resource interface
*
*/
const SEEK_CUR: Int32 = 1 /* Seek from current position. */
struct FileDescriptor {
var _fileHandle: IntNative = INVALID_HANDLE
init(fileHandle: IntNative) {
this._fileHandle = fileHandle
}
}
class ProcessInputStream <: InputStream {
var inputStream: InputStream
init(fileDescriptor: FileDescriptor) {
inputStream = PipeInputStream(fileDescriptor)
}
public func read(buffer: Array<Byte>): Int64 {
this.inputStream.read(buffer)
}
}
class ProcessOutputStream <: OutputStream {
var outputStream: OutputStream
init(fileDescriptor: FileDescriptor) {
outputStream = PipeOutputStream(fileDescriptor)
}
public func write(buffer: Array<Byte>): Unit {
this.outputStream.write(buffer)
}
public func flush(): Unit {}
}
/**
* PipeOutputStream implement OutputStream & Resource interface
*/
class PipeOutputStream <: OutputStream & Resource {
var _fileDescriptor: FileDescriptor = FileDescriptor(INVALID_HANDLE)
init(fileDescriptor: FileDescriptor) {
this._fileDescriptor = fileDescriptor
}
public func write(buffer: Array<Byte>): Unit {
if (!isHandleValid(_fileDescriptor._fileHandle)) {
throw ProcessException("The stream not opened, can not be written.")
}
if (buffer.size == 0) {
return
}
this.directWrite(buffer)
}
public func flush(): Unit {}
public func isClosed(): Bool {
return !isHandleValid(_fileDescriptor._fileHandle)
}
public func close(): Unit {
let handle = _fileDescriptor._fileHandle
if (!isHandleValid(handle)) {
return
}
this.flush()
closePipeHandle(handle)
this._fileDescriptor._fileHandle = INVALID_HANDLE
}
/**
* Write the array to the file and return the bytes successfully written into the file.
*
* @param buffer – The buffer will be written to the file
*
*
* @throws ProcessException if system failed to write the file
*/
private func directWrite(buffer: Array<Byte>): Unit {
unsafe {
let bufSize: Int64 = buffer.size
var bufPtr: CPointerHandle<Byte> = acquireArrayRawData(buffer)
let writeSuccess: Bool = CJ_OS_FileWrite(this._fileDescriptor._fileHandle, bufPtr.pointer,
UIntNative(bufSize))
releaseArrayRawData(bufPtr)
if (!writeSuccess) {
throw ProcessException("The stream write error.")
}
}
}
}
/**
* PipeInputStream implement InputStream & Resource interface
*/
class PipeInputStream <: InputStream & Resource {
var _fileDescriptor: FileDescriptor = FileDescriptor(INVALID_HANDLE)
init(fileDescriptor: FileDescriptor) {
this._fileDescriptor = fileDescriptor
}
public func read(buffer: Array<Byte>): Int64 {
if (!isHandleValid(_fileDescriptor._fileHandle)) {
throw ProcessException("The stream not opened, can not to read.")
}
if (buffer.size == 0) {
throw IllegalArgumentException("The buffer is empty.")
}
let readBytes: Int64 = directRead(buffer)
if (readBytes < 0) {
throw ProcessException("The stream read Error.")
}
return readBytes
}
public func isClosed(): Bool {
return !isHandleValid(_fileDescriptor._fileHandle)
}
public func close(): Unit {
let handle = _fileDescriptor._fileHandle
if (!isHandleValid(handle)) {
return
}
closePipeHandle(handle)
this._fileDescriptor._fileHandle = INVALID_HANDLE
}
/**
* Read from the file directly and write into buffer.
*
* @param buffer - Read to the buffer from the file
*
* @return Length successfully written into the array buffer
*/
private func directRead(buffer: Array<Byte>): Int64 {
unsafe {
let bufPtr: CPointerHandle<Byte> = acquireArrayRawData(buffer)
let readSize: Int64 = CJ_OS_FileRead(this._fileDescriptor._fileHandle, bufPtr.pointer,
UIntNative(buffer.size))
releaseArrayRawData(bufPtr)
return readSize
}
}
}
class NullProcessStream <: IOStream & Resource {
var _fileDescriptor: FileDescriptor = FileDescriptor(INVALID_HANDLE)
init() {}
public func read(_: Array<Byte>): Int64 {
return -1
}
public func write(_: Array<Byte>): Unit {
throw ProcessException("Invaild outputStream.")
}
public func flush(): Unit {}
public func isClosed(): Bool {
return !isHandleValid(_fileDescriptor._fileHandle)
}
public func close(): Unit {}
}
func closePipeHandle(handle: IntNative): Unit {
if (unsafe { CJ_OS_CloseFile(handle) } < 0) {
throw ProcessException("Failed to close stream.")
}
}