Skip to content

Commit e94b32e

Browse files
committed
[Bug 14846] com.livecode.byte: Fix "offset" and "index"
1 parent f46f63d commit e94b32e

File tree

3 files changed

+101
-30
lines changed

3 files changed

+101
-30
lines changed

libfoundation/src/foundation-data.cpp

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -662,36 +662,48 @@ bool MCDataFirstIndexOf(MCDataRef p_data, MCDataRef p_chunk, MCRange t_range, ui
662662
return t_found;
663663
}
664664

665-
666-
bool MCDataLastIndexOf(MCDataRef p_data, MCDataRef p_chunk, MCRange t_range, uindex_t& r_index)
665+
bool
666+
MCDataLastIndexOf (MCDataRef self,
667+
MCDataRef p_needle,
668+
MCRange p_range,
669+
uindex_t & r_offset)
667670
{
668-
__MCDataClampRange(p_data, t_range);
669-
670-
uindex_t t_limit, t_chunk_byte_count;
671-
t_chunk_byte_count = MCDataGetLength(p_chunk);
672-
t_limit = t_range . offset + t_range . length - t_chunk_byte_count + 1;
673-
674-
const byte_t *t_bytes = MCDataGetBytePtr(p_data);
675-
const byte_t *t_chunk_bytes = MCDataGetBytePtr(p_chunk);
676-
677-
uindex_t t_offset, t_result;
678-
t_result = 0;
679-
680-
bool t_found;
681-
t_found = false;
682-
683-
while (--t_limit)
684-
if (MCMemoryCompare(t_bytes + t_limit, t_chunk_bytes, sizeof(byte_t) * t_chunk_byte_count) == 0)
685-
{
686-
t_result = t_limit - t_range . offset;
687-
t_found = true;
688-
break;
689-
}
690-
691-
r_index = t_result;
692-
return t_found;
693-
}
671+
const byte_t *t_needle = MCDataGetBytePtr (p_needle);
672+
uindex_t t_needle_len = MCDataGetLength (p_needle);
673+
674+
/* Empty data is never found */
675+
if (0 == t_needle_len)
676+
return false;
677+
678+
__MCDataClampRange (self, p_range);
679+
680+
/* If the range is too short to contain the needle, the needle clearly
681+
* can't be found. */
682+
if (p_range.length < t_needle_len)
683+
return false;
694684

685+
const byte_t *t_haystack = MCDataGetBytePtr (self);
686+
uindex_t t_haystack_len = MCDataGetLength (self);
687+
688+
for (uindex_t t_roffset = t_needle_len - 1;
689+
t_roffset < p_range.length;
690+
++t_roffset)
691+
{
692+
/* Offset of first byte of match, relative to start of range
693+
* (i.e. t_offset = 0 for the first byte) */
694+
uindex_t t_offset = p_range.length - t_roffset - 1;
695+
696+
uindex_t t_haystack_offset = p_range.offset + t_offset;
697+
698+
if (0 == MCMemoryCompare (t_haystack + t_haystack_offset, t_needle,
699+
sizeof(byte_t) * t_needle_len))
700+
{
701+
r_offset = t_offset;
702+
return true;
703+
}
704+
}
705+
return false;
706+
}
695707

696708
#if defined(__MAC__) || defined (__IOS__)
697709
bool MCDataConvertToCFDataRef(MCDataRef p_data, CFDataRef& r_cfdata)

libscript/src/module-byte.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,13 @@ extern "C" MC_DLLEXPORT void MCByteEvalOffsetOfBytesInRange(MCDataRef p_needle,
7272
t_found = MCDataLastIndexOf(p_target, p_needle, p_range, t_offset);
7373

7474
if (t_found)
75-
t_offset++;
75+
t_offset += p_range.offset + 1;
7676
}
7777

7878
r_output = t_offset;
7979
}
8080

81-
extern "C" MC_DLLEXPORT void MCByteEvalOffsetOfBytes(MCDataRef p_needle, MCDataRef p_target, bool p_is_last, uindex_t& r_output)
81+
extern "C" MC_DLLEXPORT void MCByteEvalOffsetOfBytes(bool p_is_last, MCDataRef p_needle, MCDataRef p_target, uindex_t& r_output)
8282
{
8383
return MCByteEvalOffsetOfBytesInRange(p_needle, p_target, p_is_last, MCRangeMake(0, UINDEX_MAX), r_output);
8484
}

tests/lcb/stdlib/byte.lcb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
1717

1818
module com.livecode.byte.tests
1919

20+
use com.livecode.foreign
2021
use com.livecode.__INTERNAL._testlib
2122

2223
public handler TestEmpty()
@@ -61,4 +62,62 @@ public handler TestCodeOfByte()
6162
MCUnitTestHandlerThrows(TestCodeOfByte_Empty, "byte->code (empty)")
6263
end handler
6364

65+
----------------------------------------------------------------
66+
-- Finding subsequence offsets
67+
----------------------------------------------------------------
68+
69+
public handler TestOffset()
70+
variable N as Data
71+
variable H as Data
72+
73+
-- Only test single-byte needles for now
74+
put EncodeUTF8("x") into N
75+
put EncodeUTF8(".xx.") into H
76+
77+
test "offset (single)" when the offset of N in H is 2
78+
test "first offset (single)" when the first offset of N in H is 2
79+
test "last offset (single)" when the last offset of N in H is 3
80+
81+
put EncodeUTF8("xx") into N
82+
put EncodeUTF8(".x.x.") into H
83+
84+
test "offset (missing)" when the offset of N in H is 0
85+
86+
put EncodeUTF8("x") into N
87+
put EncodeUTF8("x") into H
88+
test "offset (single, same)" when the offset of N in H is 1
89+
test "first offset (single, same)" when the first offset of N in H is 1
90+
test "last offset (single, same)" when the last offset of N in H is 1
91+
92+
put the empty data into N
93+
put EncodeUTF8("x") into H
94+
test "offset (empty)" when the offset of N in H is 0
95+
test "first offset (empty)" when the first offset of N in H is 0
96+
test "last offset (empty)" when the last offset of N in H is 0
97+
test "offset (empty, empty)" when the offset of N in the empty data is 0
98+
99+
-- For bytes, "index" is synonymous with "offset"
100+
put EncodeUTF8("x") into N
101+
put EncodeUTF8(".xx.") into H
102+
test "index" when the index of N in H is 2
103+
end handler
104+
105+
----------------------------------------------------------------
106+
-- Helper functions
107+
----------------------------------------------------------------
108+
109+
constant kEncodingIndexUTF8 is 4
110+
111+
foreign handler MCStringEncode(in Unencoded as String, in Encoding as CInt, in IsExternalRep as CBool, out Encoded as Data) as CBool binds to "<builtin>"
112+
113+
handler EncodeUTF8(in pString as String) as Data
114+
variable tEncoded as Data
115+
variable tStatus as Boolean
116+
MCStringEncode(pString, kEncodingIndexUTF8, false, tEncoded)
117+
if tEncoded is empty then
118+
return the empty data
119+
end if
120+
return tEncoded
121+
end handler
122+
64123
end module

0 commit comments

Comments
 (0)