From 3d41937567d0728d8c834299360b4f6ee2934293 Mon Sep 17 00:00:00 2001 From: asahi3g Date: Tue, 17 Dec 2019 20:54:09 +0100 Subject: [PATCH 1/3] Add opcodes for reading binary files Opened files are tracked by i32 instead of str --- cx/constcodes_base.go | 8 ++ cx/op_gltext.go | 9 +- cx/op_os.go | 234 +++++++++++++++++++++++++++++++++++++----- cx/opcodes_base.go | 52 +++++++++- 4 files changed, 272 insertions(+), 31 deletions(-) diff --git a/cx/constcodes_base.go b/cx/constcodes_base.go index ced51e7ef..df289485b 100644 --- a/cx/constcodes_base.go +++ b/cx/constcodes_base.go @@ -28,6 +28,10 @@ const ( //CONST_OS_FILEMODE_TYPE CONST_OS_FILEMODE_PERM + CONST_OS_SEEK_SET + CONST_OS_SEEK_CUR + CONST_OS_SEEK_END + // json CONST_JSON_TOKEN_NULL CONST_JSON_TOKEN_DELIM @@ -76,6 +80,10 @@ func init() { //AddConstCode( CONST_OS_FILEMODE_TYPE , "os.ModeType" , TYPE_I32, FromI32(2399666176)) AddConstCode(CONST_OS_FILEMODE_PERM, "os.ModePerm", TYPE_I32, FromI32(511)) + AddConstCode(CONST_OS_SEEK_SET, "os.SEEK_SET", TYPE_I32, FromI32(OS_SEEK_SET)) + AddConstCode(CONST_OS_SEEK_CUR, "os.SEEK_CUR", TYPE_I32, FromI32(OS_SEEK_CUR)) + AddConstCode(CONST_OS_SEEK_END, "os.SEEK_END", TYPE_I32, FromI32(OS_SEEK_END)) + // json AddConstCode(CONST_JSON_TOKEN_NULL, "json.TOKEN_NULL", TYPE_I32, FromI32(JSON_TOKEN_NULL)) AddConstCode(CONST_JSON_TOKEN_DELIM, "json.TOKEN_DELIM", TYPE_I32, FromI32(JSON_TOKEN_DELIM)) diff --git a/cx/op_gltext.go b/cx/op_gltext.go index 8a6ea6836..6a66a801d 100644 --- a/cx/op_gltext.go +++ b/cx/op_gltext.go @@ -15,11 +15,10 @@ func op_gltext_LoadTrueType(prgrm *CXProgram) { fp := prgrm.GetFramePointer() inp1, inp2, inp3, inp4, inp5, inp6 := expr.Inputs[0], expr.Inputs[1], expr.Inputs[2], expr.Inputs[3], expr.Inputs[4], expr.Inputs[5] - - if theFont, err := gltext.LoadTruetype(openFiles[ReadStr(fp, inp2)], ReadI32(fp, inp3), rune(ReadI32(fp, inp4)), rune(ReadI32(fp, inp5)), gltext.Direction(ReadI32(fp, inp6))); err == nil { - fonts[ReadStr(fp, inp1)] = theFont - } else { - panic(err) + if file := validFile(ReadI32(fp, inp1)); file != nil { + if theFont, err := gltext.LoadTruetype(file, ReadI32(fp, inp3), rune(ReadI32(fp, inp4)), rune(ReadI32(fp, inp5)), gltext.Direction(ReadI32(fp, inp6))); err == nil { + fonts[ReadStr(fp, inp2)] = theFont + } } } diff --git a/cx/op_os.go b/cx/op_os.go index b7d039156..2523667a1 100644 --- a/cx/op_os.go +++ b/cx/op_os.go @@ -4,7 +4,9 @@ package cxcore import ( "bytes" + "encoding/binary" //"fmt" + "github.com/amherag/skycoin/src/cipher/encoder" "io/ioutil" "math" "os" @@ -12,53 +14,237 @@ import ( "strings" "syscall" "time" +) - "github.com/amherag/skycoin/src/cipher/encoder" +const ( + OS_SEEK_SET = iota + OS_SEEK_CUR + OS_SEEK_END ) -var openFiles map[string]*os.File = make(map[string]*os.File, 0) +var openFiles []*os.File +var freeFiles []int32 -func op_os_ReadFile(prgrm *CXProgram) { - expr := prgrm.GetExpr() - fp := prgrm.GetFramePointer() +// helper function used to validate json handle from expr +func validFileFromExpr(expr *CXExpression, fp int) *os.File { + handle := ReadI32(fp, expr.Inputs[0]) + return validFile(handle) +} - inp1, out1 := expr.Inputs[0], expr.Outputs[0] +// helper function used to validate file handle from i32 +func validFile(handle int32) *os.File { + if handle >= 0 && handle < int32(len(openFiles)) && openFiles[handle] != nil { + return openFiles[handle] + } + return nil +} - _ = out1 +func op_os_ReadAllText(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() - if byts, err := ioutil.ReadFile(ReadStr(fp, inp1)); err == nil { - _ = byts - // sByts := encoder.Serialize(byts) - // assignOutput(0, sByts, "[]byte", expr, call) - } else { - panic(err) + var success bool + if byts, err := ioutil.ReadFile(ReadStr(fp, expr.Inputs[0])); err == nil { + WriteObject(GetFinalOffset(fp, expr.Outputs[0]), encoder.Serialize(string(byts))) + success = true } + + WriteBool(GetFinalOffset(fp, expr.Outputs[1]), success) } func op_os_Open(prgrm *CXProgram) { expr := prgrm.GetExpr() fp := prgrm.GetFramePointer() - inp1 := expr.Inputs[0] - name := ReadStr(fp, inp1) - if file, err := os.Open(name); err == nil { - openFiles[name] = file - } else { - panic(err) + handle := int32(-1) + + if file, err := os.Open(ReadStr(fp, expr.Inputs[0])); err == nil { + freeCount := len(freeFiles) + if freeCount > 0 { + freeCount-- + handle = int32(freeFiles[freeCount]) + freeFiles = freeFiles[:freeCount] + } else { + handle = int32(len(openFiles)) + openFiles = append(openFiles, nil) + } + + if handle < 0 || handle >= int32(len(openFiles)) { + panic("internal error") + } + + openFiles[handle] = file } + + WriteI32(GetFinalOffset(fp, expr.Outputs[0]), int32(handle)) } func op_os_Close(prgrm *CXProgram) { expr := prgrm.GetExpr() fp := prgrm.GetFramePointer() - inp1 := expr.Inputs[0] - name := ReadStr(fp, inp1) - if file, ok := openFiles[name]; ok { - if err := file.Close(); err != nil { - panic(err) + success := false + + handle := ReadI32(fp, expr.Inputs[0]) + if file := validFile(handle); file != nil { + if err := file.Close(); err == nil { + success = true + } + + openFiles[handle] = nil + freeFiles = append(freeFiles, handle) + } + + WriteBool(GetFinalOffset(fp, expr.Outputs[0]), success) +} + +func op_os_Seek(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() + + offset := int64(-1) + if file := validFileFromExpr(expr, fp); file != nil { + var err error + if offset, err = file.Seek(ReadI64(fp, expr.Inputs[1]), int(ReadI32(fp, expr.Inputs[2]))); err != nil { + offset = -1 + } + } + WriteI64(GetFinalOffset(fp, expr.Outputs[0]), offset) +} + +func op_os_ReadF32(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() + + var value float32 + var success bool + + if file := validFileFromExpr(expr, fp); file != nil { + if err := binary.Read(file, binary.LittleEndian, &value); err == nil { + success = true + } + } + + WriteF32(GetFinalOffset(fp, expr.Outputs[0]), value) + WriteBool(GetFinalOffset(fp, expr.Outputs[1]), success) +} + +func op_os_ReadF32Slice(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() + + var success bool + + outputSlicePointer := GetFinalOffset(fp, expr.Outputs[0]) + outputSliceOffset := GetPointerOffset(int32(outputSlicePointer)) + count := ReadI32(fp, expr.Inputs[1]) + if count > 0 { + if file := validFileFromExpr(expr, fp); file != nil { + values := make([]float32, count) + if err := binary.Read(file, binary.LittleEndian, values); err == nil { + success = true + outputSliceOffset = int32(sliceResize(outputSliceOffset, count, 4)) + outputSliceData := GetSliceData(outputSliceOffset, 4) + for i := int32(0); i < count; i++ { + WriteMemF32(outputSliceData, int(i*4), values[i]) + } + } + } + } + + WriteI32(outputSlicePointer, outputSliceOffset) + WriteBool(GetFinalOffset(fp, expr.Outputs[1]), success) + +} + +func op_os_ReadUI32(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() + + var value uint32 + var success bool + + if file := validFileFromExpr(expr, fp); file != nil { + if err := binary.Read(file, binary.LittleEndian, &value); err == nil { + success = true + } + } + + WriteUI32(GetFinalOffset(fp, expr.Outputs[0]), value) + WriteBool(GetFinalOffset(fp, expr.Outputs[1]), success) +} + +func op_os_ReadUI32Slice(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() + + var success bool + + outputSlicePointer := GetFinalOffset(fp, expr.Outputs[0]) + outputSliceOffset := GetPointerOffset(int32(outputSlicePointer)) + count := ReadI32(fp, expr.Inputs[1]) + if count > 0 { + if file := validFileFromExpr(expr, fp); file != nil { + values := make([]uint32, count) + if err := binary.Read(file, binary.LittleEndian, values); err == nil { + success = true + outputSliceOffset = int32(sliceResize(outputSliceOffset, count, 4)) + outputSliceData := GetSliceData(outputSliceOffset, 4) + for i := int32(0); i < count; i++ { + WriteMemUI32(outputSliceData, int(i*4), values[i]) + } + } + } + } + + WriteI32(outputSlicePointer, outputSliceOffset) + WriteBool(GetFinalOffset(fp, expr.Outputs[1]), success) + +} + +func op_os_ReadUI16(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() + + var value uint16 + var success bool + + if file := validFileFromExpr(expr, fp); file != nil { + if err := binary.Read(file, binary.LittleEndian, &value); err == nil { + success = true } } + + WriteUI16(GetFinalOffset(fp, expr.Outputs[0]), value) + WriteBool(GetFinalOffset(fp, expr.Outputs[1]), success) +} + +func op_os_ReadUI16Slice(prgrm *CXProgram) { + expr := prgrm.GetExpr() + fp := prgrm.GetFramePointer() + + var success bool + + outputSlicePointer := GetFinalOffset(fp, expr.Outputs[0]) + outputSliceOffset := GetPointerOffset(int32(outputSlicePointer)) + count := ReadI32(fp, expr.Inputs[1]) + if count > 0 { + if file := validFileFromExpr(expr, fp); file != nil { + values := make([]uint16, count) + if err := binary.Read(file, binary.LittleEndian, values); err == nil { + success = true + outputSliceOffset = int32(sliceResize(outputSliceOffset, count, 2)) + outputSliceData := GetSliceData(outputSliceOffset, 2) + for i := int32(0); i < count; i++ { + WriteMemUI16(outputSliceData, int(i*2), values[i]) + } + } + } + } + + WriteI32(outputSlicePointer, outputSliceOffset) + WriteBool(GetFinalOffset(fp, expr.Outputs[1]), success) + } func op_os_GetWorkingDirectory(prgrm *CXProgram) { diff --git a/cx/opcodes_base.go b/cx/opcodes_base.go index a0ef3dceb..83e01d4f4 100644 --- a/cx/opcodes_base.go +++ b/cx/opcodes_base.go @@ -17,6 +17,14 @@ const ( OP_OS_GET_WORKING_DIRECTORY OP_OS_OPEN OP_OS_CLOSE + OP_OS_SEEK + OP_OS_READ_ALL_TEXT + OP_OS_READ_F32 + OP_OS_READ_UI32 + OP_OS_READ_UI16 + OP_OS_READ_F32_SLICE + OP_OS_READ_UI32_SLICE + OP_OS_READ_UI16_SLICE OP_OS_RUN OP_OS_EXIT @@ -64,10 +72,34 @@ func init() { []*CXArgument{newOpPar(TYPE_STR, false)}) AddOpCode(OP_OS_OPEN, "os.Open", []*CXArgument{newOpPar(TYPE_STR, false)}, - []*CXArgument{}) + []*CXArgument{newOpPar(TYPE_I32, false)}) AddOpCode(OP_OS_CLOSE, "os.Close", + []*CXArgument{newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_BOOL, false)}) + AddOpCode(OP_OS_SEEK, "os.Seek", + []*CXArgument{newOpPar(TYPE_I32, false), newOpPar(TYPE_I64, false), newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_I64, false)}) + AddOpCode(OP_OS_READ_F32, "os.ReadF32", + []*CXArgument{newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_F32, false), newOpPar(TYPE_BOOL, false)}) + AddOpCode(OP_OS_READ_UI32, "os.ReadUI32", + []*CXArgument{newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_UI32, false), newOpPar(TYPE_BOOL, false)}) + AddOpCode(OP_OS_READ_UI16, "os.ReadUI16", + []*CXArgument{newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_UI16, false), newOpPar(TYPE_BOOL, false)}) + AddOpCode(OP_OS_READ_F32_SLICE, "os.ReadF32Slice", + []*CXArgument{newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_F32, true), newOpPar(TYPE_BOOL, false)}) + AddOpCode(OP_OS_READ_UI32_SLICE, "os.ReadUI32Slice", + []*CXArgument{newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_UI32, true), newOpPar(TYPE_BOOL, false)}) + AddOpCode(OP_OS_READ_UI16_SLICE, "os.ReadUI16Slice", + []*CXArgument{newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_UI16, true), newOpPar(TYPE_BOOL, false)}) + AddOpCode(OP_OS_READ_ALL_TEXT, "os.ReadAllText", []*CXArgument{newOpPar(TYPE_STR, false)}, - []*CXArgument{}) + []*CXArgument{newOpPar(TYPE_STR, false), newOpPar(TYPE_BOOL, false)}) AddOpCode(OP_OS_RUN, "os.Run", []*CXArgument{newOpPar(TYPE_STR, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_STR, false)}, []*CXArgument{newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_STR, false)}) @@ -130,6 +162,22 @@ func init() { return op_os_Open case OP_OS_CLOSE: return op_os_Close + case OP_OS_SEEK: + return op_os_Seek + case OP_OS_READ_F32: + return op_os_ReadF32 + case OP_OS_READ_UI32: + return op_os_ReadUI32 + case OP_OS_READ_UI16: + return op_os_ReadUI16 + case OP_OS_READ_F32_SLICE: + return op_os_ReadF32Slice + case OP_OS_READ_UI32_SLICE: + return op_os_ReadUI32Slice + case OP_OS_READ_UI16_SLICE: + return op_os_ReadUI16Slice + case OP_OS_READ_ALL_TEXT: + return op_os_ReadAllText case OP_OS_RUN: return op_os_Run case OP_OS_EXIT: From b59ce679e8117258a8ee451c18e3e64a536d59d0 Mon Sep 17 00:00:00 2001 From: asahi3g Date: Tue, 17 Dec 2019 21:08:16 +0100 Subject: [PATCH 2/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cd144482..068176837 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Import statements are now aware of the possibility of importing libraries that are defined in a CX workspace. - If the user has not set a CXPATH through an environment variable or --cxpath flag, CX will use by default `~/cx` and create all the necessary subdirectories. - If the directory supplied by the user to be used as CXPATH does not contain the following subdirectories: `src/`, `pkg/` and `bin/`, CX will create these subdirectories. + - Added opcodes for reading binary files : os.Seek, os.ReadUI16, os.ReadUI32, os.ReadF32, os.ReadUI16Slice, os.ReadUI32Slice, os.ReadF32Slice. * Changes * Removed cx-games as a module. It was just confusing as users would be redirected to an outdated version of the repo and the games are already From 48530487b3e2cae03c48df894c64d2b6cc1d55f4 Mon Sep 17 00:00:00 2001 From: asahi3g Date: Tue, 17 Dec 2019 22:22:50 +0100 Subject: [PATCH 3/3] Fix gltext.LoadTrueType signature --- cx/opcodes_opengl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cx/opcodes_opengl.go b/cx/opcodes_opengl.go index f224b8ebd..d40e1c4f4 100644 --- a/cx/opcodes_opengl.go +++ b/cx/opcodes_opengl.go @@ -681,7 +681,7 @@ func init() { // gltext AddOpCode(OP_GLTEXT_LOAD_TRUE_TYPE, "gltext.LoadTrueType", - []*CXArgument{newOpPar(TYPE_STR, false), newOpPar(TYPE_STR, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false)}, + []*CXArgument{newOpPar(TYPE_I32, false), newOpPar(TYPE_STR, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false), newOpPar(TYPE_I32, false)}, []*CXArgument{}) AddOpCode(OP_GLTEXT_PRINTF, "gltext.Printf", []*CXArgument{newOpPar(TYPE_STR, false), newOpPar(TYPE_F32, false), newOpPar(TYPE_F32, false), newOpPar(TYPE_STR, false)},