@@ -215,41 +215,51 @@ static void sendReady() { writeMessage(MESSAGE_READY, "ready"); }
215215static void sendAck () { writeMessage (MESSAGE_ACK, " ack" ); }
216216
217217// This method may modify the bytes in the buffer
218+ // Scala's BigInt.toString(16) follows the format of
219+ // `s"${if(value<0) "-" else ""}${value.abs.toString(16)}"`
218220static void sendBits (uint8_t *mutableBytes, int bitCount, bool isSigned) {
219221 if (bitCount <= 0 ) {
220222 failWithError (" Cannot send 0-bit value." );
221223 }
222- if (isSigned && bitCount <= 1 ) {
223- failWithError (" Cannot send 1-bit signed value." );
224- }
225224 writeMessageStart (MESSAGE_BITS);
226225 writeMessageBody (" %08X " , bitCount) int byteCount = (bitCount + 7 ) / 8 ;
227226 if (isSigned) {
228227 uint8_t signBitMask;
228+ // A very dirty way to sign-extend the most significant byte
229+ // when the signed number is negative
230+ uint8_t lastByteNegativePad;
229231 switch (bitCount % 8 ) {
230232 case 1 :
231233 signBitMask = 0b00000001 ;
234+ lastByteNegativePad = 0b11111110 ;
232235 break ;
233236 case 2 :
234237 signBitMask = 0b00000010 ;
238+ lastByteNegativePad = 0b11111100 ;
235239 break ;
236240 case 3 :
237241 signBitMask = 0b00000100 ;
242+ lastByteNegativePad = 0b11111000 ;
238243 break ;
239244 case 4 :
240245 signBitMask = 0b00001000 ;
246+ lastByteNegativePad = 0b11110000 ;
241247 break ;
242248 case 5 :
243249 signBitMask = 0b00010000 ;
250+ lastByteNegativePad = 0b11100000 ;
244251 break ;
245252 case 6 :
246253 signBitMask = 0b00100000 ;
254+ lastByteNegativePad = 0b11000000 ;
247255 break ;
248256 case 7 :
249257 signBitMask = 0b01000000 ;
258+ lastByteNegativePad = 0b10000000 ;
250259 break ;
251260 case 0 :
252261 signBitMask = 0b10000000 ;
262+ lastByteNegativePad = 0b00000000 ;
253263 break ;
254264 }
255265 if (mutableBytes[byteCount - 1 ] & signBitMask) {
@@ -258,13 +268,17 @@ static void sendBits(uint8_t *mutableBytes, int bitCount, bool isSigned) {
258268 int carry = 1 ;
259269 for (int i = 0 ; i < byteCount; i++) {
260270 int byte = mutableBytes[i];
271+ // We need to sign-extend the last byte
272+ if (i == byteCount - 1 ) {
273+ byte = mutableBytes[i] | lastByteNegativePad;
274+ }
261275 byte = (~byte & 0xFF ) + carry;
262276 carry = byte >> 8 ;
263277 mutableBytes[i] = (uint8_t )byte;
264278 }
279+ // Since we sign-extended the number,
280+ // two's compliment just works, no need to strip bits (#4593)
265281 }
266- // Strip irrelevant bits
267- mutableBytes[byteCount - 1 ] &= signBitMask - 1 ;
268282 }
269283 for (int i = byteCount - 1 ; i >= 0 ; i--) {
270284 writeMessageBody (" %02X" , mutableBytes[i]);
@@ -410,6 +424,9 @@ int scanHexByteReverse(const char **reverseScanCursor,
410424}
411425
412426/* *
427+ * Scala's BigInt.toString(16) follows the format of
428+ * `s"${if(value<0) "-" else ""}${value.abs.toString(16)}"`
429+ *
413430 * Returned value must be manually freed.
414431 */
415432static uint8_t *scanHexBits (const char **scanCursor, const char *scanEnd,
@@ -423,21 +440,18 @@ static uint8_t *scanHexBits(const char **scanCursor, const char *scanEnd,
423440 }
424441
425442 bool isNegative;
426- int valueBitCount;
427443 if (**scanCursor == ' -' ) {
428444 (*scanCursor)++;
429445 if (reverseScanCursor < *scanCursor) {
430446 failWithError (" Unexpected end of negative value when %s." , description);
431447 }
432448 isNegative = true ;
433- if (bitCount <= 1 ) {
434- failWithError (" Cannot scan 1 -bit-wide negative value when %s." ,
449+ if (bitCount < 1 ) {
450+ failWithError (" Cannot scan 0 -bit-wide negative value when %s." ,
435451 description);
436452 }
437- valueBitCount = bitCount - 1 ;
438453 } else {
439454 isNegative = false ;
440- valueBitCount = bitCount;
441455 }
442456
443457 int byteCount = (bitCount + 7 ) / 8 ;
@@ -447,7 +461,7 @@ static uint8_t *scanHexBits(const char **scanCursor, const char *scanEnd,
447461 const char *firstCharacterOfValue = *scanCursor;
448462 int carry = 1 ; // Only used when `isNegative` is true
449463 int scannedByteCount = 0 ;
450- int valueByteCount = (valueBitCount + 7 ) / 8 ;
464+ int valueByteCount = (bitCount + 7 ) / 8 ;
451465 while (scannedByteCount < valueByteCount) {
452466 int scannedByte = scanHexByteReverse (&reverseScanCursor,
453467 firstCharacterOfValue, description);
@@ -473,11 +487,10 @@ static uint8_t *scanHexBits(const char **scanCursor, const char *scanEnd,
473487 // A mask of the "inapplicable" bits in the high order byte, used to determine
474488 // if we received too many bits for the value we are trying to scan. This
475489 // value could be calculated with bitwise operations, but I find a table to be
476- // cleaner and easier to understand. We use `valueBitCount` instead of
477- // `bitCount` because the sign bit should be `1` for negative numbers along
478- // with all of the other leading bits.
490+ // cleaner and easier to understand. There's no sign bit in Scala's `BigInt.toString(16)`,
491+ // instead a minus sign will be present.
479492 uint8_t highOrderByteMask;
480- switch (valueBitCount % 8 ) {
493+ switch (bitCount % 8 ) {
481494 case 1 :
482495 highOrderByteMask = 0b11111110 ;
483496 break ;
0 commit comments