#ifndef NAME_H
#define NAME_H
typedef struct name_block name_block_t;
struct name_block {
uint64_t backslashes;
uint64_t dots;
};
nonnull_all
static really_inline void copy_name_block(
name_block_t *block, const char *text, uint8_t *wire)
{
simd_8x32_t input;
simd_loadu_8x32(&input, text);
simd_storeu_8x32(wire, &input);
block->backslashes = simd_find_8x32(&input, '\\');
block->dots = simd_find_8x32(&input, '.');
}
nonnull_all
static really_inline int32_t scan_name(
const char *data,
size_t tlength,
uint8_t octets[255 + ZONE_BLOCK_SIZE],
size_t *lengthp)
{
uint64_t label = 0;
const char *text = data;
uint8_t *wire = octets + 1;
name_block_t block;
octets[0] = 0;
copy_name_block(&block, text, wire);
uint64_t count = 32, length = 0, base = 0, left = tlength;
uint64_t carry = 0;
if (tlength < 32)
count = tlength;
uint64_t mask = (1llu << count) - 1u;
if (unlikely(block.backslashes & mask))
goto escaped;
if (unlikely(block.dots & 1llu))
return ((*lengthp = tlength) == 1 ? 0 : -1);
length = count;
block.dots &= mask;
carry = (block.dots >> (length - 1));
if (unlikely(block.dots & (block.dots >> 1)))
return -1;
if (likely(block.dots)) {
count = trailing_zeroes(block.dots);
block.dots = clear_lowest_bit(block.dots);
octets[label] = (uint8_t)count;
label = count + 1;
while (block.dots) {
count = trailing_zeroes(block.dots);
block.dots = clear_lowest_bit(block.dots);
octets[label] = (uint8_t)(count - label);
label = count + 1;
}
}
octets[label] = (uint8_t)(length - label);
if (tlength <= 32)
return (void)(*lengthp = length + 1), carry == 0;
text += length;
wire += length;
left -= length;
do {
copy_name_block(&block, text, wire);
count = 32;
if (left < 32)
count = left;
mask = (1llu << count) - 1u;
base = length;
if (unlikely(block.backslashes & mask)) {
escaped:
block.backslashes &= -block.backslashes;
mask = block.backslashes - 1;
block.dots &= mask;
count = count_ones(mask);
const uint32_t octet = unescape(text+count, wire+count);
if (!octet)
return -1;
text += count + octet;
wire += count + 1;
length += count + 1;
left -= count + octet;
count += 1;
} else {
block.dots &= mask;
text += count;
wire += count;
length += count;
left -= count;
}
if (unlikely(block.dots & ((block.dots >> 1) | carry)))
return -1;
carry = block.dots >> (count - 1);
if (likely(block.dots)) {
count = trailing_zeroes(block.dots) + base;
block.dots = clear_lowest_bit(block.dots);
octets[label] = (uint8_t)(count - label);
if (unlikely(count - label > 63))
return -1;
label = count + 1;
while (block.dots) {
count = trailing_zeroes(block.dots) + base;
block.dots = clear_lowest_bit(block.dots);
octets[label] = (uint8_t)(count - label);
label = count + 1;
}
} else {
if (length - label > 63)
return -1;
}
octets[label] = (uint8_t)(length - label);
} while (left && length < 255);
if (length >= 255)
return -1;
*lengthp = length + 1;
return carry == 0;
}
#endif