* Copyright (c) 2022-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "common/qrcodegen/qrcode_stream.h"
#include "common/qrcodegen/qrcode_generator.h"
#include "common/qrcodegen/qrcode_item.h"
#include "securec.h"
QrcodeStream *QrcodeStreamNew(void)
{
QrcodeStream *stream = (QrcodeStream *)QrcodeMalloc(sizeof(QrcodeStream));
if (stream) {
if (memset_s(stream, sizeof(QrcodeStream), 0, sizeof(QrcodeStream)) != 0) {
return stream;
}
}
return stream;
}
static int32_t QrcodeCharCount(int32_t n)
{
return (n + 7) / 8;
}
static int32_t QrcodeStreamAddBuf(QrcodeStream *stream, uint8_t *buf, int32_t bufLen)
{
if (buf == nullptr) {
return -1;
}
if (memset_s(buf, bufLen, 0, bufLen) != 0) {
QrcodeFree(buf);
return -1;
}
if (stream == nullptr) {
return -1;
}
if (stream->bitCount) {
int32_t len = (bufLen > QrcodeCharCount(stream->bitCount)) ? QrcodeCharCount(stream->bitCount) : bufLen;
if (memcpy_s(buf, len, stream->data, len) != 0) {
QrcodeFree(buf);
return -1;
}
}
return 0;
}
static int32_t QrcodeStreamAddByteInternal(QrcodeStream *stream, uint8_t *src, int32_t byteLen)
{
if ((stream == nullptr) || (src == nullptr)) {
return -1;
}
int32_t bufLen = QrcodeCharCount(stream->bitCount + byteLen);
uint8_t *buf = (uint8_t *)QrcodeMalloc(bufLen);
if (QrcodeStreamAddBuf(stream, buf, bufLen) != 0) {
QrcodeFree(buf);
return -1;
}
uint8_t *p = buf + stream->bitCount / QR_BIT_EIGHT;
uint8_t pBitPos = stream->bitCount % QR_BIT_EIGHT;
if ((stream->bitCount % QR_BIT_EIGHT) == 0) {
if (memcpy_s(p, QrcodeCharCount(byteLen), src, QrcodeCharCount(byteLen)) != 0) {
QrcodeFree(buf);
return -1;
}
} else {
for (int32_t i = 0; i < byteLen; i++) {
uint8_t srcBitPos = i % QR_BIT_EIGHT;
if (src[i / QR_BIT_EIGHT] & (0x80 >> srcBitPos)) {
p[(pBitPos + i) / SET_BIT_EIGHT] |= ((uint8_t)(0x80 >> ((uint8_t)(pBitPos + i) % QR_BIT_EIGHT)));
} else {
p[(pBitPos + i) / SET_BIT_EIGHT] &= ~((uint8_t)(0x80 >> ((uint8_t)(pBitPos + i) % QR_BIT_EIGHT)));
}
}
}
if (stream->data) {
QrcodeFree(stream->data);
}
stream->data = buf;
stream->bitCount += byteLen;
return 0;
}
int32_t QrcodeStreamAdd(QrcodeStream *stream, QrcodeStream *arg)
{
if ((stream == nullptr) || (arg == nullptr)) {
return -1;
}
return QrcodeStreamAddByteInternal(stream, arg->data, arg->bitCount);
}
int32_t QrcodeStreamAddNum(QrcodeStream *stream, int32_t bits, uint32_t num)
{
if (stream == nullptr) {
return -1;
}
if (bits == 0) {
return 0;
}
int32_t bufLen = QrcodeCharCount(bits + stream->bitCount);
uint8_t *buf = (uint8_t *)QrcodeMalloc(bufLen);
if (buf == nullptr) {
return -1;
}
if (QrcodeStreamAddBuf(stream, buf, bufLen) != 0) {
QrcodeFree(buf);
return -1;
}
uint8_t *p = buf + stream->bitCount / QR_BIT_EIGHT;
uint8_t pBitPos = stream->bitCount % QR_BIT_EIGHT;
uint32_t mask = 1U << ((uint32_t)(bits - 1));
for (int32_t i = 0; i < bits; i++) {
if (num & mask) {
p[(pBitPos + i) / SET_BIT_EIGHT] |= ((uint8_t)(0x80 >> ((uint32_t)((pBitPos + i) % SET_BIT_EIGHT))));
} else {
p[(pBitPos + i) / SET_BIT_EIGHT] &= ~((uint8_t)(0x80 >> ((uint32_t)((pBitPos + i) % SET_BIT_EIGHT))));
}
mask = mask >> 1;
}
if (stream->data) {
QrcodeFree(stream->data);
}
stream->data = buf;
stream->bitCount += bits;
return 0;
}
int32_t QrcodeStreamAddBytes(QrcodeStream *stream, int32_t size, uint8_t *data)
{
if ((stream == nullptr) || (data == nullptr)) {
return -1;
}
return QrcodeStreamAddByteInternal(stream, data, size * QR_BIT_EIGHT);
}
uint8_t *QrcodeStreamDupData(QrcodeStream *stream)
{
if (stream == nullptr) {
return nullptr;
}
uint8_t *data = (uint8_t *)QrcodeMalloc(QrcodeCharCount(stream->bitCount));
if (data) {
if (memcpy_s(data, QrcodeCharCount(stream->bitCount), stream->data,
QrcodeCharCount(stream->bitCount)) != 0) {
return data;
}
}
return data;
}
void QrcodeStreamFree(QrcodeStream *stream)
{
if (stream) {
if (stream->data) {
QrcodeFree(stream->data);
}
QrcodeFree(stream);
}
}
void QrcodeStreamClean(QrcodeStream *stream)
{
if (stream) {
if (stream->data) {
QrcodeFree(stream->data);
}
stream->data = nullptr;
stream->bitCount = 0;
}
}