Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nonstandard _sub(), _setSub() and _concat() for RawData #179

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions MiniScript-cpp/rdTest.ms
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,43 @@ testRawData = function
qa.assertEqual r.utf8(0, 5), "hello"
qa.assertEqual r.utf8(-10, 5), "hello"
qa.assertEqual r.utf8(1, 3), "ell"
qa.assertEqual r.utf8(1, 100), null

r.resize 7
r.setUtf8 0, "hello world"
qa.assertEqual r.utf8(0), "hello w"

// _sub()
qa.assertEqual r._sub.utf8, "hello w"
qa.assertEqual r._sub(0).utf8, "hello w"
qa.assertEqual r._sub(2).utf8, "llo w"
qa.assertEqual r._sub(2, 3).utf8, "llo"
qa.assertEqual r._sub(2, 100), null
qa.assertEqual r._sub(-5, 3).utf8, "llo"

// _setSub()
r2 = new RawData
r2.resize 2
r2.setUtf8 0, "xx"
r._setSub 0, r2
qa.assertEqual r.utf8, "xxllo w"
r._setSub 3, r2
qa.assertEqual r.utf8, "xxlxx w"
r._setSub 6, r2
qa.assertEqual r.utf8, "xxlxx x"

// _concat()
qa.assertEqual RawData._concat([]).len, 0
r1 = new RawData
r1.resize 4
r1.setUtf8 0, "hell"
r2 = new RawData
r2.resize 4
r2.setUtf8 0, "o wo"
r3 = new RawData
r3.resize 3
r3.setUtf8 0, "rld"
qa.assertEqual RawData._concat([r1, r2, r3]).utf8, "hello world"
end function

if refEquals(locals, globals) then testRawData
110 changes: 110 additions & 0 deletions MiniScript-cpp/src/ShellIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ class RawDataHandleStorage : public RefCountedStorage {
fread(data, 1, dataSize, f);
}
}
RawDataHandleStorage(const char *buf, long nBytes) {
data = nullptr;
resize(nBytes);
if (nBytes > 0) {
memcpy(data, buf, nBytes);
}
}
virtual ~RawDataHandleStorage() { free(data); }
void resize(size_t newSize) {
if (newSize == 0) {
Expand All @@ -115,6 +122,16 @@ class RawDataHandleStorage : public RefCountedStorage {
}
}
}
void copyFromOther(RawDataHandleStorage& other, long offset, long maxBytes, long otherOffset, long otherBytes) {
if (offset >= dataSize || otherOffset >= other.dataSize) return;
if (maxBytes < 0 || offset + maxBytes > dataSize) maxBytes = dataSize - offset;
if (maxBytes < 1) return;
if (otherBytes < 0 || otherOffset + otherBytes > other.dataSize) otherBytes = other.dataSize - otherOffset;
if (otherBytes < 1) return;
if (otherBytes > maxBytes) otherBytes = maxBytes;
char *dst = (char *)data + offset;
memcpy(dst, other.data, otherBytes);
}

void *data;
size_t dataSize;
Expand Down Expand Up @@ -167,6 +184,9 @@ Intrinsic *i_rawDataDouble = nullptr;
Intrinsic *i_rawDataSetDouble = nullptr;
Intrinsic *i_rawDataUtf8 = nullptr;
Intrinsic *i_rawDataSetUtf8 = nullptr;
Intrinsic *i_rawDataSub = nullptr;
Intrinsic *i_rawDataSetSub = nullptr;
Intrinsic *i_rawDataConcat = nullptr;

Intrinsic *i_keyAvailable = nullptr;
Intrinsic *i_keyGet = nullptr;
Expand Down Expand Up @@ -1143,6 +1163,77 @@ static IntrinsicResult intrinsic_rawDataSetUtf8(Context *context, IntrinsicResul
return IntrinsicResult(nBytes);
}

// _sub: Returns a fragment of RawData as another RawData object.
static IntrinsicResult intrinsic_rawDataSub(Context *context, IntrinsicResult partialResult) {
Value self = context->GetVar("self");
long offset = context->GetVar("offset").IntValue();
long nBytes = context->GetVar("bytes").IntValue();
const char *data = (const char *)rawDataGetBytes(self, offset, nBytes, rdnaNull);
if (!data) return IntrinsicResult::Null;
Value dataWrapper = Value::NewHandle(new RawDataHandleStorage(data, nBytes));
ValueDict instance;
instance.SetValue(Value::magicIsA, RawDataType());
instance.SetValue(_handle, dataWrapper);
Value result(instance);
return IntrinsicResult(result);
}

// _setSub: Rewrites a frament of RawData with another RawData.
static IntrinsicResult intrinsic_rawDataSetSub(Context *context, IntrinsicResult partialResult) {
Value self = context->GetVar("self");
long offset = context->GetVar("offset").IntValue();
Value other = context->GetVar("rawData");
if (!self.IsA(RawDataType(), context->vm)) TypeException("RawData parameter is required").raise();
if (!other.IsA(RawDataType(), context->vm)) TypeException("RawData parameter is required").raise();
Value selfDataWrapper = self.Lookup(_handle);
if (selfDataWrapper.IsNull() or selfDataWrapper.type != ValueType::Handle) return IntrinsicResult::Null;
Value otherDataWrapper = other.Lookup(_handle);
if (otherDataWrapper.IsNull() or otherDataWrapper.type != ValueType::Handle) return IntrinsicResult::Null;
if (Value::Equality(selfDataWrapper, otherDataWrapper)) RuntimeException("cannot copy RawData into itself").raise();
RawDataHandleStorage *selfStorage = (RawDataHandleStorage*)selfDataWrapper.data.ref;
RawDataHandleStorage *otherStorage = (RawDataHandleStorage*)otherDataWrapper.data.ref;
selfStorage->copyFromOther(*otherStorage, offset, -1, 0, -1);
return IntrinsicResult::Null;
}

// _concat: Joins several RawData objects into a single one.
static IntrinsicResult intrinsic_rawDataConcat(Context *context, IntrinsicResult partialResult) {
Value rawDataListV = context->GetVar("rawDataList");
if (rawDataListV.type != ValueType::List) TypeException("List parameter is required").raise();
ValueList rawDataList = rawDataListV.GetList();
ValueList wrappers;
ValueList offsets;
long totalBytes = 0;
for (int i=0; i<rawDataList.Count(); i++) {
Value elem = rawDataList[i];
if (!elem.IsA(RawDataType(), context->vm)) {
TypeException(String("element ") + String::Format(i, "%d") + " should be a RawData object").raise();
}
Value elemDataWrapper = elem.Lookup(_handle);
if (elemDataWrapper.IsNull() or elemDataWrapper.type != ValueType::Handle) continue;
RawDataHandleStorage *elemStorage = (RawDataHandleStorage*)elemDataWrapper.data.ref;
if (elemStorage->dataSize > 0) {
wrappers.Add(elemDataWrapper);
offsets.Add(totalBytes);
totalBytes += elemStorage->dataSize;
}
}
RawDataHandleStorage *storage = new RawDataHandleStorage();
storage->resize(totalBytes);
for (int i=0; i<wrappers.Count(); i++) {
Value elemDataWrapper = wrappers[i];
long offset = offsets[i].IntValue();
RawDataHandleStorage *elemStorage = (RawDataHandleStorage*)elemDataWrapper.data.ref;
storage->copyFromOther(*elemStorage, offset, -1, 0, -1);
}
Value dataWrapper = Value::NewHandle(storage);
ValueDict instance;
instance.SetValue(Value::magicIsA, RawDataType());
instance.SetValue(_handle, dataWrapper);
Value result(instance);
return IntrinsicResult(result);
}

static IntrinsicResult intrinsic_keyAvailable(Context *context, IntrinsicResult partialResult) {
return IntrinsicResult(KeyAvailable());
}
Expand Down Expand Up @@ -1350,6 +1441,9 @@ static ValueDict& RawDataType() {
result.SetValue("setDouble", i_rawDataSetDouble->GetFunc());
result.SetValue("utf8", i_rawDataUtf8->GetFunc());
result.SetValue("setUtf8", i_rawDataSetUtf8->GetFunc());
result.SetValue("_sub", i_rawDataSub->GetFunc());
result.SetValue("_setSub", i_rawDataSetSub->GetFunc());
result.SetValue("_concat", i_rawDataConcat->GetFunc());
}

return result;
Expand Down Expand Up @@ -1752,6 +1846,22 @@ void AddShellIntrinsics() {
i_rawDataSetUtf8->AddParam("value", "");
i_rawDataSetUtf8->code = &intrinsic_rawDataSetUtf8;

i_rawDataSub = Intrinsic::Create("");
i_rawDataSub->AddParam("self");
i_rawDataSub->AddParam("offset", 0);
i_rawDataSub->AddParam("bytes", -1);
i_rawDataSub->code = &intrinsic_rawDataSub;

i_rawDataSetSub = Intrinsic::Create("");
i_rawDataSetSub->AddParam("self");
i_rawDataSetSub->AddParam("offset", 0);
i_rawDataSetSub->AddParam("rawData");
i_rawDataSetSub->code = &intrinsic_rawDataSetSub;

i_rawDataConcat = Intrinsic::Create("");
i_rawDataConcat->AddParam("rawDataList");
i_rawDataConcat->code = &intrinsic_rawDataConcat;

// END RawData methods


Expand Down