From 570a83ae0d2cb1dc06d6acc66dd78160278a0ac8 Mon Sep 17 00:00:00 2001 From: Davin Shearer <2205472+scholarsmate@users.noreply.github.com> Date: Sun, 17 Oct 2021 17:04:41 -0400 Subject: [PATCH] add bit offset support (#10) * add bit offset support * demonstrate different display modes * add right and left buffer shifts * update bindings * add viewport destroy --- .gitignore | 9 +- omega_edit/omega_edit.cpp | 91 ++++++++++-- omega_edit/omega_edit.h | 18 ++- omega_edit/omega_edit_wrap.cxx | 255 ++++++++++++++++++++++++++++++++- tests/omega_test.cpp | 110 ++++++++++++-- tests/test_utils.h | 39 ++++- 6 files changed, 483 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 4ca2a4bf1..6728b922c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ -# generate files +# generated files node_modules/ build/ -cmake-build-debug/ +cmake-build-*/ # log files -*.log \ No newline at end of file +*.log + +# IDE files +.idea/ diff --git a/omega_edit/omega_edit.cpp b/omega_edit/omega_edit.cpp index 2c8832883..86b7d2d37 100644 --- a/omega_edit/omega_edit.cpp +++ b/omega_edit/omega_edit.cpp @@ -81,6 +81,7 @@ struct viewport_t { on_change_cbk cbk{}; void *user_data_ptr{}; vector data; + uint8_t bit_offset{}; }; const author_t *get_viewport_author(const viewport_t *viewport_ptr) { @@ -107,13 +108,21 @@ void *get_viewport_user_data(const viewport_t *viewport_ptr) { return viewport_ptr->user_data_ptr; } +uint8_t get_viewport_bit_offset(const viewport_t *viewport_ptr) { + return viewport_ptr->bit_offset; +} + +typedef vector > author_vector_t; +typedef vector > viewport_vector_t; +typedef vector change_vector_t; + struct session_t { FILE *file_ptr{}; int64_t serial{}; int64_t computed_file_size{}; - vector > authors; - vector > viewports; - vector changes; + author_vector_t authors; + viewport_vector_t viewports; + change_vector_t changes; vector changes_by_offset; }; @@ -121,6 +130,40 @@ struct session_t { // FUNCTIONS // +int left_shift_buffer(uint8_t *array, int64_t len, uint8_t shift_left) { + int rc = -1; + if (shift_left > 0 && shift_left < 8) { + uint8_t shift_right = 8 - shift_left; + uint8_t mask = ((1 << shift_left) - 1) << shift_right; + uint8_t bits1 = 0; + for (auto i = len - 1; i >= 0; --i) { + auto bits2 = array[i] & mask; + array[i] <<= shift_left; + array[i] |= bits1 >> shift_right; + bits1 = bits2; + } + rc = 0; + } + return rc; +} + +int right_shift_buffer(uint8_t *array, int64_t len, uint8_t shift_right) { + int rc = -1; + if (shift_right > 0 && shift_right < 8) { + uint8_t shift_left = 8 - shift_right; + uint8_t mask = (1 << shift_right) - 1; + uint8_t bits1 = 0; + for (auto i = len - 1; i >= 0; --i) { + auto bits2 = array[i] & mask; + array[i] >>= shift_right; + array[i] |= bits1 << shift_left; + bits1 = bits2; + } + rc = 0; + } + return rc; +} + session_t *create_session(FILE *file_ptr) { fseek(file_ptr, 0L, SEEK_END); auto *session_ptr = new session_t; @@ -147,7 +190,8 @@ session_t *get_author_session(const author_t *author_ptr) { } viewport_t * -add_viewport(const author_t *author_ptr, int64_t offset, int32_t capacity, on_change_cbk cbk, void *user_data_ptr) { +add_viewport(const author_t *author_ptr, int64_t offset, int32_t capacity, on_change_cbk cbk, void *user_data_ptr, + uint8_t bit_offset) { auto viewport_ptr = shared_ptr(new viewport_t); viewport_ptr->author_ptr = author_ptr; viewport_ptr->computed_offset = offset; @@ -156,31 +200,52 @@ add_viewport(const author_t *author_ptr, int64_t offset, int32_t capacity, on_ch viewport_ptr->data.reserve(capacity); viewport_ptr->cbk = cbk; viewport_ptr->user_data_ptr = user_data_ptr; + viewport_ptr->bit_offset = bit_offset; author_ptr->session_ptr->viewports.push_back(viewport_ptr); // TODO: populate the viewport and call the on change callback read_segment(author_ptr->session_ptr->file_ptr, offset, author_ptr->session_ptr->computed_file_size, viewport_ptr->data.data(), viewport_ptr->capacity, - &viewport_ptr->length); + &viewport_ptr->length, viewport_ptr->bit_offset); (*viewport_ptr->cbk)(viewport_ptr.get(), nullptr); return viewport_ptr.get(); } -int set_viewport(viewport_t *viewport_ptr, int64_t offset, int32_t capacity) { +int destroy_viewport(const viewport_t *viewport_ptr) { + int rc = -1; + viewport_vector_t *session_viewport_ptr = &viewport_ptr->author_ptr->session_ptr->viewports; + for (auto iter = session_viewport_ptr->begin(); iter != session_viewport_ptr->end(); ++iter) { + if (viewport_ptr == iter->get()) { + session_viewport_ptr->erase(iter); + rc = 0; + break; + } + } + return rc; +} + +int set_viewport(viewport_t *viewport_ptr, int64_t offset, int32_t capacity, uint8_t bit_offset) { // only change settings if they are different - if (viewport_ptr->computed_offset != offset || viewport_ptr->capacity != capacity) { + if (viewport_ptr->computed_offset != offset || viewport_ptr->capacity != capacity || + viewport_ptr->bit_offset != bit_offset) { viewport_ptr->computed_offset = offset; viewport_ptr->capacity = capacity; viewport_ptr->data.reserve(capacity); + viewport_ptr->bit_offset = bit_offset; // TODO: update viewport and call the on change callback read_segment(viewport_ptr->author_ptr->session_ptr->file_ptr, offset, viewport_ptr->author_ptr->session_ptr->computed_file_size, viewport_ptr->data.data(), viewport_ptr->capacity, - &viewport_ptr->length); + &viewport_ptr->length, + viewport_ptr->bit_offset); (*viewport_ptr->cbk)(viewport_ptr, nullptr); } return 0; } +size_t num_viewports(const session_t *session_ptr) { + return session_ptr->viewports.size(); +} + // Internal function to add a change to the given session int add_change_(const change_t *change_ptr) { auto session_ptr = change_ptr->author_ptr->session_ptr; @@ -286,12 +351,15 @@ size_t num_changes_by_author(const author_t *author_ptr) { } int read_segment(FILE *from_file_ptr, int64_t offset, int64_t file_size, uint8_t *buffer, int64_t capacity, - int64_t *length) { + int64_t *length, uint8_t bit_offset) { auto len = file_size - offset; if (len > 0) { *length = (len < capacity) ? len : capacity; fseek(from_file_ptr, offset, SEEK_SET); fread(buffer, 1, *length, from_file_ptr); + if (bit_offset > 0) { + left_shift_buffer(buffer, *length, bit_offset); + } } return 0; } @@ -368,11 +436,6 @@ int save(const author_t *author_ptr, FILE *file_ptr) { return 0; } -viewport_t *add_viewport(const author_t *author_ptr, int32_t capacity, on_change_cbk cbk, void *user_data_ptr) { - // TODO: Implement - return nullptr; -} - // returns 1 if a change was found and undone and 0 if no change was found int undo(const author_t *author_ptr) { int rc = 0; diff --git a/omega_edit/omega_edit.h b/omega_edit/omega_edit.h index c2ae00cfc..6e664e8d8 100644 --- a/omega_edit/omega_edit.h +++ b/omega_edit/omega_edit.h @@ -50,6 +50,8 @@ const uint8_t *get_viewport_data(const viewport_t *viewport_ptr); void *get_viewport_user_data(const viewport_t *viewport_ptr); +uint8_t get_viewport_bit_offset(const viewport_t *viewport_ptr); + // Returns the author's name from the given author structure const char *get_author_name(const author_t *author_ptr); @@ -63,7 +65,10 @@ const author_t *add_author(session_t *session_ptr, const char *author_name); // Add a viewport to the given session viewport_t * -add_viewport(const author_t *author_ptr, int64_t offset, int32_t capacity, on_change_cbk cbk, void *user_data_ptr); +add_viewport(const author_t *author_ptr, int64_t offset, int32_t capacity, on_change_cbk cbk, void *user_data_ptr, + uint8_t bit_offset); + +int destroy_viewport(const viewport_t *viewport_ptr); // Destroy the given session void destroy_session(session_t *session_ptr); @@ -86,7 +91,10 @@ int64_t offset_to_computed_offset(const session_t *session_ptr, int64_t offset); int64_t computed_offset_to_offset(const session_t *session_ptr, int64_t offset); // Set viewport at the given offset (return 0 on success, non-zero otherwise) -int set_viewport(viewport_t *viewport_ptr, int64_t offset, int32_t capacity); +int set_viewport(viewport_t *viewport_ptr, int64_t offset, int32_t capacity, uint8_t bit_offset); + +// Number of active viewports in this given session +size_t num_viewports(const session_t *session_ptr); // Undo the last change for this author from the given session (return 0 on success, non-zero otherwise) int undo(const author_t *author_ptr); @@ -95,8 +103,12 @@ int undo(const author_t *author_ptr); int save(const author_t *author_ptr, FILE *file_ptr); int read_segment(FILE *from_file_ptr, int64_t offset, int64_t file_size, uint8_t *buffer, int64_t capacity, - int64_t *length); + int64_t *length, uint8_t bit_offset); int write_segment(FILE *from_file_ptr, int64_t offset, int64_t byte_count, FILE *to_file_ptr); +int left_shift_buffer(uint8_t *array, int64_t len, uint8_t shift_left); + +int right_shift_buffer(uint8_t *array, int64_t len, uint8_t shift_right); + #endif //OMEGA_OMEGA_EDIT_H diff --git a/omega_edit/omega_edit_wrap.cxx b/omega_edit/omega_edit_wrap.cxx index 3c8e44c67..c91df6913 100644 --- a/omega_edit/omega_edit_wrap.cxx +++ b/omega_edit/omega_edit_wrap.cxx @@ -2061,6 +2061,34 @@ static SwigV8ReturnValue _wrap_get_viewport_user_data(const SwigV8Arguments &arg } +static SwigV8ReturnValue _wrap_get_viewport_bit_offset(const SwigV8Arguments &args) { + SWIGV8_HANDLESCOPE(); + + v8::Handle jsresult; + viewport_t *arg1 = (viewport_t *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + uint8_t result; + + if(args.Length() != 1) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_get_viewport_bit_offset."); + + res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_viewport_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "get_viewport_bit_offset" "', argument " "1"" of type '" "viewport_t const *""'"); + } + arg1 = reinterpret_cast< viewport_t * >(argp1); + result = get_viewport_bit_offset((viewport_t const *)arg1); + jsresult = SWIG_NewPointerObj((new uint8_t(static_cast< const uint8_t& >(result))), SWIGTYPE_p_uint8_t, SWIG_POINTER_OWN | 0 ); + + + SWIGV8_RETURN(jsresult); + + goto fail; +fail: + SWIGV8_RETURN(SWIGV8_UNDEFINED()); +} + + static SwigV8ReturnValue _wrap_get_author_name(const SwigV8Arguments &args) { SWIGV8_HANDLESCOPE(); @@ -2192,6 +2220,7 @@ static SwigV8ReturnValue _wrap_add_viewport(const SwigV8Arguments &args) { int32_t arg3 ; on_change_cbk arg4 = (on_change_cbk) 0 ; void *arg5 = (void *) 0 ; + uint8_t arg6 ; void *argp1 = 0 ; int res1 = 0 ; void *argp2 ; @@ -2199,9 +2228,11 @@ static SwigV8ReturnValue _wrap_add_viewport(const SwigV8Arguments &args) { void *argp3 ; int res3 = 0 ; int res5 ; + void *argp6 ; + int res6 = 0 ; viewport_t *result = 0 ; - if(args.Length() != 5) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_add_viewport."); + if(args.Length() != 6) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_add_viewport."); res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_author_t, 0 | 0 ); if (!SWIG_IsOK(res1)) { @@ -2240,7 +2271,18 @@ static SwigV8ReturnValue _wrap_add_viewport(const SwigV8Arguments &args) { if (!SWIG_IsOK(res5)) { SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "add_viewport" "', argument " "5"" of type '" "void *""'"); } - result = (viewport_t *)add_viewport((author_t const *)arg1,arg2,arg3,arg4,arg5); + { + res6 = SWIG_ConvertPtr(args[5], &argp6, SWIGTYPE_p_uint8_t, 0 ); + if (!SWIG_IsOK(res6)) { + SWIG_exception_fail(SWIG_ArgError(res6), "in method '" "add_viewport" "', argument " "6"" of type '" "uint8_t""'"); + } + if (!argp6) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "add_viewport" "', argument " "6"" of type '" "uint8_t""'"); + } else { + arg6 = *(reinterpret_cast< uint8_t * >(argp6)); + } + } + result = (viewport_t *)add_viewport((author_t const *)arg1,arg2,arg3,arg4,arg5,arg6); jsresult = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_viewport_t, 0 | 0 ); @@ -2254,6 +2296,34 @@ static SwigV8ReturnValue _wrap_add_viewport(const SwigV8Arguments &args) { } +static SwigV8ReturnValue _wrap_destroy_viewport(const SwigV8Arguments &args) { + SWIGV8_HANDLESCOPE(); + + v8::Handle jsresult; + viewport_t *arg1 = (viewport_t *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int result; + + if(args.Length() != 1) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_destroy_viewport."); + + res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_viewport_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "destroy_viewport" "', argument " "1"" of type '" "viewport_t const *""'"); + } + arg1 = reinterpret_cast< viewport_t * >(argp1); + result = (int)destroy_viewport((viewport_t const *)arg1); + jsresult = SWIG_From_int(static_cast< int >(result)); + + + SWIGV8_RETURN(jsresult); + + goto fail; +fail: + SWIGV8_RETURN(SWIGV8_UNDEFINED()); +} + + static SwigV8ReturnValue _wrap_destroy_session(const SwigV8Arguments &args) { SWIGV8_HANDLESCOPE(); @@ -2638,15 +2708,18 @@ static SwigV8ReturnValue _wrap_set_viewport(const SwigV8Arguments &args) { viewport_t *arg1 = (viewport_t *) 0 ; int64_t arg2 ; int32_t arg3 ; + uint8_t arg4 ; void *argp1 = 0 ; int res1 = 0 ; void *argp2 ; int res2 = 0 ; void *argp3 ; int res3 = 0 ; + void *argp4 ; + int res4 = 0 ; int result; - if(args.Length() != 3) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_set_viewport."); + if(args.Length() != 4) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_set_viewport."); res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_viewport_t, 0 | 0 ); if (!SWIG_IsOK(res1)) { @@ -2675,7 +2748,18 @@ static SwigV8ReturnValue _wrap_set_viewport(const SwigV8Arguments &args) { arg3 = *(reinterpret_cast< int32_t * >(argp3)); } } - result = (int)set_viewport(arg1,arg2,arg3); + { + res4 = SWIG_ConvertPtr(args[3], &argp4, SWIGTYPE_p_uint8_t, 0 ); + if (!SWIG_IsOK(res4)) { + SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "set_viewport" "', argument " "4"" of type '" "uint8_t""'"); + } + if (!argp4) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "set_viewport" "', argument " "4"" of type '" "uint8_t""'"); + } else { + arg4 = *(reinterpret_cast< uint8_t * >(argp4)); + } + } + result = (int)set_viewport(arg1,arg2,arg3,arg4); jsresult = SWIG_From_int(static_cast< int >(result)); @@ -2687,6 +2771,34 @@ static SwigV8ReturnValue _wrap_set_viewport(const SwigV8Arguments &args) { } +static SwigV8ReturnValue _wrap_num_viewports(const SwigV8Arguments &args) { + SWIGV8_HANDLESCOPE(); + + v8::Handle jsresult; + session_t *arg1 = (session_t *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + size_t result; + + if(args.Length() != 1) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_num_viewports."); + + res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_session_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "num_viewports" "', argument " "1"" of type '" "session_t const *""'"); + } + arg1 = reinterpret_cast< session_t * >(argp1); + result = num_viewports((session_t const *)arg1); + jsresult = SWIG_From_size_t(static_cast< size_t >(result)); + + + SWIGV8_RETURN(jsresult); + + goto fail; +fail: + SWIGV8_RETURN(SWIGV8_UNDEFINED()); +} + + static SwigV8ReturnValue _wrap_undo(const SwigV8Arguments &args) { SWIGV8_HANDLESCOPE(); @@ -2762,6 +2874,7 @@ static SwigV8ReturnValue _wrap_read_segment(const SwigV8Arguments &args) { uint8_t *arg4 = (uint8_t *) 0 ; int64_t arg5 ; int64_t *arg6 = (int64_t *) 0 ; + uint8_t arg7 ; void *argp1 = 0 ; int res1 = 0 ; void *argp2 ; @@ -2774,9 +2887,11 @@ static SwigV8ReturnValue _wrap_read_segment(const SwigV8Arguments &args) { int res5 = 0 ; void *argp6 = 0 ; int res6 = 0 ; + void *argp7 ; + int res7 = 0 ; int result; - if(args.Length() != 6) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_read_segment."); + if(args.Length() != 7) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_read_segment."); res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_FILE, 0 | 0 ); if (!SWIG_IsOK(res1)) { @@ -2826,7 +2941,18 @@ static SwigV8ReturnValue _wrap_read_segment(const SwigV8Arguments &args) { SWIG_exception_fail(SWIG_ArgError(res6), "in method '" "read_segment" "', argument " "6"" of type '" "int64_t *""'"); } arg6 = reinterpret_cast< int64_t * >(argp6); - result = (int)read_segment(arg1,arg2,arg3,arg4,arg5,arg6); + { + res7 = SWIG_ConvertPtr(args[6], &argp7, SWIGTYPE_p_uint8_t, 0 ); + if (!SWIG_IsOK(res7)) { + SWIG_exception_fail(SWIG_ArgError(res7), "in method '" "read_segment" "', argument " "7"" of type '" "uint8_t""'"); + } + if (!argp7) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "read_segment" "', argument " "7"" of type '" "uint8_t""'"); + } else { + arg7 = *(reinterpret_cast< uint8_t * >(argp7)); + } + } + result = (int)read_segment(arg1,arg2,arg3,arg4,arg5,arg6,arg7); jsresult = SWIG_From_int(static_cast< int >(result)); @@ -2905,6 +3031,118 @@ static SwigV8ReturnValue _wrap_write_segment(const SwigV8Arguments &args) { } +static SwigV8ReturnValue _wrap_left_shift_buffer(const SwigV8Arguments &args) { + SWIGV8_HANDLESCOPE(); + + v8::Handle jsresult; + uint8_t *arg1 = (uint8_t *) 0 ; + int64_t arg2 ; + uint8_t arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 ; + int res2 = 0 ; + void *argp3 ; + int res3 = 0 ; + int result; + + if(args.Length() != 3) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_left_shift_buffer."); + + res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_uint8_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "left_shift_buffer" "', argument " "1"" of type '" "uint8_t *""'"); + } + arg1 = reinterpret_cast< uint8_t * >(argp1); + { + res2 = SWIG_ConvertPtr(args[1], &argp2, SWIGTYPE_p_int64_t, 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "left_shift_buffer" "', argument " "2"" of type '" "int64_t""'"); + } + if (!argp2) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "left_shift_buffer" "', argument " "2"" of type '" "int64_t""'"); + } else { + arg2 = *(reinterpret_cast< int64_t * >(argp2)); + } + } + { + res3 = SWIG_ConvertPtr(args[2], &argp3, SWIGTYPE_p_uint8_t, 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "left_shift_buffer" "', argument " "3"" of type '" "uint8_t""'"); + } + if (!argp3) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "left_shift_buffer" "', argument " "3"" of type '" "uint8_t""'"); + } else { + arg3 = *(reinterpret_cast< uint8_t * >(argp3)); + } + } + result = (int)left_shift_buffer(arg1,arg2,arg3); + jsresult = SWIG_From_int(static_cast< int >(result)); + + + SWIGV8_RETURN(jsresult); + + goto fail; +fail: + SWIGV8_RETURN(SWIGV8_UNDEFINED()); +} + + +static SwigV8ReturnValue _wrap_right_shift_buffer(const SwigV8Arguments &args) { + SWIGV8_HANDLESCOPE(); + + v8::Handle jsresult; + uint8_t *arg1 = (uint8_t *) 0 ; + int64_t arg2 ; + uint8_t arg3 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 ; + int res2 = 0 ; + void *argp3 ; + int res3 = 0 ; + int result; + + if(args.Length() != 3) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_right_shift_buffer."); + + res1 = SWIG_ConvertPtr(args[0], &argp1,SWIGTYPE_p_uint8_t, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "right_shift_buffer" "', argument " "1"" of type '" "uint8_t *""'"); + } + arg1 = reinterpret_cast< uint8_t * >(argp1); + { + res2 = SWIG_ConvertPtr(args[1], &argp2, SWIGTYPE_p_int64_t, 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "right_shift_buffer" "', argument " "2"" of type '" "int64_t""'"); + } + if (!argp2) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "right_shift_buffer" "', argument " "2"" of type '" "int64_t""'"); + } else { + arg2 = *(reinterpret_cast< int64_t * >(argp2)); + } + } + { + res3 = SWIG_ConvertPtr(args[2], &argp3, SWIGTYPE_p_uint8_t, 0 ); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "right_shift_buffer" "', argument " "3"" of type '" "uint8_t""'"); + } + if (!argp3) { + SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "right_shift_buffer" "', argument " "3"" of type '" "uint8_t""'"); + } else { + arg3 = *(reinterpret_cast< uint8_t * >(argp3)); + } + } + result = (int)right_shift_buffer(arg1,arg2,arg3); + jsresult = SWIG_From_int(static_cast< int >(result)); + + + SWIGV8_RETURN(jsresult); + + goto fail; +fail: + SWIGV8_RETURN(SWIGV8_UNDEFINED()); +} + + /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ static swig_type_info _swigt__p_FILE = {"_p_FILE", "FILE *", 0, 0, (void*)0, 0}; @@ -3293,11 +3531,13 @@ SWIGV8_AddStaticFunction(exports_obj, "get_viewport_length", _wrap_get_viewport_ SWIGV8_AddStaticFunction(exports_obj, "get_viewport_computed_offset", _wrap_get_viewport_computed_offset); SWIGV8_AddStaticFunction(exports_obj, "get_viewport_data", _wrap_get_viewport_data); SWIGV8_AddStaticFunction(exports_obj, "get_viewport_user_data", _wrap_get_viewport_user_data); +SWIGV8_AddStaticFunction(exports_obj, "get_viewport_bit_offset", _wrap_get_viewport_bit_offset); SWIGV8_AddStaticFunction(exports_obj, "get_author_name", _wrap_get_author_name); SWIGV8_AddStaticFunction(exports_obj, "get_author_session", _wrap_get_author_session); SWIGV8_AddStaticFunction(exports_obj, "create_session", _wrap_create_session); SWIGV8_AddStaticFunction(exports_obj, "add_author", _wrap_add_author); SWIGV8_AddStaticFunction(exports_obj, "add_viewport", _wrap_add_viewport); +SWIGV8_AddStaticFunction(exports_obj, "destroy_viewport", _wrap_destroy_viewport); SWIGV8_AddStaticFunction(exports_obj, "destroy_session", _wrap_destroy_session); SWIGV8_AddStaticFunction(exports_obj, "ovr", _wrap_ovr); SWIGV8_AddStaticFunction(exports_obj, "del", _wrap_del); @@ -3308,10 +3548,13 @@ SWIGV8_AddStaticFunction(exports_obj, "get_computed_file_size", _wrap_get_comput SWIGV8_AddStaticFunction(exports_obj, "offset_to_computed_offset", _wrap_offset_to_computed_offset); SWIGV8_AddStaticFunction(exports_obj, "computed_offset_to_offset", _wrap_computed_offset_to_offset); SWIGV8_AddStaticFunction(exports_obj, "set_viewport", _wrap_set_viewport); +SWIGV8_AddStaticFunction(exports_obj, "num_viewports", _wrap_num_viewports); SWIGV8_AddStaticFunction(exports_obj, "undo", _wrap_undo); SWIGV8_AddStaticFunction(exports_obj, "save", _wrap_save); SWIGV8_AddStaticFunction(exports_obj, "read_segment", _wrap_read_segment); SWIGV8_AddStaticFunction(exports_obj, "write_segment", _wrap_write_segment); +SWIGV8_AddStaticFunction(exports_obj, "left_shift_buffer", _wrap_left_shift_buffer); +SWIGV8_AddStaticFunction(exports_obj, "right_shift_buffer", _wrap_right_shift_buffer); /* register classes */ diff --git a/tests/omega_test.cpp b/tests/omega_test.cpp index fff581a68..9a5fb2531 100644 --- a/tests/omega_test.cpp +++ b/tests/omega_test.cpp @@ -22,6 +22,35 @@ #include #include "../omega_edit/omega_edit.h" +TEST_CASE("Buffer Shift", "[BufferShift]") { + auto const fill = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + auto *buffer = (uint8_t *) strdup(fill); + auto buff_len = (int64_t) strlen((const char *) buffer); + + // Shift the buffer 3 bits to the right + auto rc = right_shift_buffer(buffer, buff_len, 3); + REQUIRE(rc == 0); + // Shift the buffer 5 bits to the right + rc = right_shift_buffer(buffer, buff_len, 5); + REQUIRE(rc == 0); + // We shifted a total of 8 bits (one byte) to the right, so compare the buffer against the fill plus one byte + REQUIRE(strcmp((const char *) fill + 1, (const char *) buffer) == 0); + + // Reset the buffer + memcpy(buffer, fill, buff_len); + REQUIRE(strcmp((const char *) fill, (const char *) buffer) == 0); + + // Shift the buffer 6 bits to the left + rc = left_shift_buffer(buffer, buff_len, 6); + REQUIRE(rc == 0); + // Shift the buffer 2 bits to the left + rc = left_shift_buffer(buffer, buff_len, 2); + REQUIRE(rc == 0); + // We shifted a total of 8 bits (one byte) to the left, so compare the buffer against the fill plus one byte + REQUIRE(strcmp((const char *) fill + 1, (const char *) buffer) == 0); + + free(buffer); +} TEST_CASE("File Compare", "[UtilTests]") { SECTION("Identity") { @@ -93,16 +122,42 @@ TEST_CASE("Check initialization", "[InitTests]") { } } +enum display_mode_t { + BIT_MODE, BYTE_MODE, CHAR_MODE +}; +struct view_mode_t { + enum display_mode_t display_mode = CHAR_MODE; +}; + void change_cbk(const viewport_t *viewport_ptr, const change_t *change_ptr) { if (change_ptr) { fprintf(stdout, "Change Author: %s\n", get_author_name(get_author(change_ptr))); } - fprintf(stdout, "'%s' viewport, capacity: %lld, length: %lld, offset: %lld\n[", + fprintf(stdout, "'%s' viewport, capacity: %lld, length: %lld, offset: %lld, bit offset: %u", get_author_name(get_viewport_author(viewport_ptr)), get_viewport_capacity(viewport_ptr), get_viewport_length(viewport_ptr), - get_viewport_computed_offset(viewport_ptr)); - fwrite(get_viewport_data(viewport_ptr), 1, get_viewport_length(viewport_ptr), stdout); - fprintf(stdout, "]\n"); + get_viewport_computed_offset(viewport_ptr), get_viewport_bit_offset(viewport_ptr)); + if (get_viewport_user_data(viewport_ptr)) { + auto const *view_mode_ptr = (const view_mode_t *) get_viewport_user_data(viewport_ptr); + switch (view_mode_ptr->display_mode) { + case BIT_MODE: + fprintf(stdout, "\n BIT MODE ["); + write_pretty_bits(get_viewport_data(viewport_ptr), get_viewport_length(viewport_ptr), stdout); + fprintf(stdout, "]\n"); + break; + case CHAR_MODE: + fprintf(stdout, "\nCHAR MODE ["); + fwrite(get_viewport_data(viewport_ptr), 1, get_viewport_length(viewport_ptr), stdout); + fprintf(stdout, "]\n"); + break; + default: // flow through + case BYTE_MODE: + fprintf(stdout, "\nBYTE MODE ["); + write_pretty_bytes(get_viewport_data(viewport_ptr), get_viewport_length(viewport_ptr), stdout); + fprintf(stdout, "]\n"); + break; + } + } fflush(stdout); } @@ -115,14 +170,53 @@ TEST_CASE("File Viewing", "[InitTests]") { session_t *session_ptr; const author_t *author_ptr; viewport_t *viewport_ptr; + view_mode_t view_mode; session_ptr = create_session(test_infile_ptr); author_ptr = add_author(session_ptr, author_name); - viewport_ptr = add_viewport(author_ptr, 0, 10, change_cbk, nullptr); - for(int64_t offset(0); offset < get_computed_file_size(session_ptr); ++offset) { - set_viewport(viewport_ptr, offset, 10 + (offset % 40)); + auto viewport_count = num_viewports(session_ptr); + REQUIRE(viewport_count == 0); + view_mode.display_mode = BIT_MODE; + viewport_ptr = add_viewport(author_ptr, 0, 10, change_cbk, &view_mode, 0); + REQUIRE(viewport_count + 1 == num_viewports(session_ptr)); + view_mode.display_mode = CHAR_MODE; + change_cbk(viewport_ptr, nullptr); + for (int64_t offset(0); offset < get_computed_file_size(session_ptr); ++offset) { + set_viewport(viewport_ptr, offset, 10 + (offset % 40), 0); } - set_viewport(viewport_ptr, 0, 20); + + // Change the display mode from character mode to byte mode to handle non-standard byte alignment + + view_mode.display_mode = BIT_MODE; + set_viewport(viewport_ptr, 0, 20, 0); + + // Change to bit offsets + set_viewport(viewport_ptr, 0, 20, 1); + set_viewport(viewport_ptr, 0, 20, 2); + set_viewport(viewport_ptr, 0, 20, 3); + set_viewport(viewport_ptr, 0, 20, 4); + set_viewport(viewport_ptr, 0, 20, 5); + set_viewport(viewport_ptr, 0, 20, 6); + set_viewport(viewport_ptr, 0, 20, 7); + + view_mode.display_mode = BYTE_MODE; + change_cbk(viewport_ptr, nullptr); + + // Copy the contents of the 6-bit offset viewport into a buffer and shift it 1 more bit to get back on 8-bit + // alignment for simple comparison with the original fill + auto *buffer = (uint8_t *) malloc(get_viewport_capacity(viewport_ptr)); + memcpy(buffer, get_viewport_data(viewport_ptr), get_viewport_length(viewport_ptr)); + auto rc = left_shift_buffer(buffer, get_viewport_length(viewport_ptr), 1); + REQUIRE(rc == 0); + REQUIRE(memcmp(buffer, fill + 1, get_viewport_length(viewport_ptr) - 1) == 0); + free(buffer); + + rc = ins(author_ptr, 3, 4, '+'); + REQUIRE(rc == 0); + viewport_count = num_viewports(session_ptr); + rc = destroy_viewport(viewport_ptr); + REQUIRE(rc == 0); + REQUIRE(viewport_count - 1 == num_viewports(session_ptr)); destroy_session(session_ptr); remove(file_name); diff --git a/tests/test_utils.h b/tests/test_utils.h index 950041340..ac0ab7a4d 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -23,7 +23,9 @@ #define DEBUG #ifdef DEBUG + #include + #define DBG(x) do{x}while(0) #else #define DBG(x) @@ -47,17 +49,17 @@ inline int compare_file_pointers(FILE *f1, FILE *f2) { return (feof(f1) && feof(f2)) ? 0 : 1; } -inline int compare_files(const char * f1, const char * f2) { - FILE * f1_ptr = fopen(f1, "r"); - FILE * f2_ptr = fopen(f2, "r"); +inline int compare_files(const char *f1, const char *f2) { + FILE *f1_ptr = fopen(f1, "r"); + FILE *f2_ptr = fopen(f2, "r"); auto result = compare_file_pointers(f1_ptr, f2_ptr); fclose(f1_ptr); fclose(f2_ptr); return result; } -inline FILE * fill_file(const char * f1, int64_t file_size, const char * fill, uint64_t fill_length) { - FILE * f1_ptr = fopen(f1, "w+"); +inline FILE *fill_file(const char *f1, int64_t file_size, const char *fill, uint64_t fill_length) { + FILE *f1_ptr = fopen(f1, "w+"); while (file_size) { auto count = (fill_length > file_size) ? file_size : fill_length; fwrite(fill, 1, count, f1_ptr); @@ -68,4 +70,31 @@ inline FILE * fill_file(const char * f1, int64_t file_size, const char * fill, u return f1_ptr; } +inline void write_pretty_bits_byte(uint8_t byte, FILE * out_fp) { + for (auto i = 7; 0 <= i; --i) { + fprintf(out_fp, "%c", (byte & (1 << i)) ? '1' : '0'); + } +} + +inline void write_pretty_bits(const uint8_t *ptr, int64_t size, FILE *out_fp) { + if (size > 0) { + auto i = 0; + write_pretty_bits_byte(ptr[i++], out_fp); + while (i < size) { + fprintf(out_fp, " "); + write_pretty_bits_byte(ptr[i++], out_fp); + } + } +} + +inline void write_pretty_bytes(const uint8_t *ptr, int64_t size, FILE *out_fp) { + if (size > 0) { + auto i = 0; + fprintf(out_fp, "%02hhX", ptr[i++]); + while (i < size) { + fprintf(out_fp, " %02hhX", ptr[i++]); + } + } +} + #endif //OMEGA_EDIT_TEST_UTILS_H