LINUX.ORG.RU

Lua Base64

 ,


1

2

Наговнокодил вот, может кому пригодится, работает под

  • LuaJit
  • Lua5.1 с дополнительным внешним модулем bit32
  • Lua5.2
  • Lua5.3
  • Lua5.4

Пример:

local base64 = require("base64")
local base = base64.encode("Hello World!")
local text = base64.decode("SGVsbG8gV29ybGQh")
print(base,text)

Свой алфавит кодирования

local base64 = require("base64")

local basename = 'mybase64'
local alphabet = 'ABCDEFGcdefghijHIJKLMN0123456789*?abkOPQRSTUVWXYZlmnopqrstuvwxyz'
local endcode  = '@'

assert(base64.register(basename,alphabet,endcode))
local base = base64.encode("Hello World!","mybase64")
local text = base64.decode("KGNV5Gw*Nqxm5GI?","mybase64")
print(base,text)

Днищекод:

Вроде правильно работает.
Всякую фигню принимал в base64 из сети, вроде норм.
Досвиданья

Перемещено leave из talks

★★★★★

Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)

Ответ на: комментарий от TeopeTuK

Понятия не имею, это жертва NIH синдрома :)
А чем они друг от друга отличаются? :D
Я не претендую на замену чего либо, надо было, взял и накалякал, глянув википедию и уточняя моменты в RFC4648 до тех пор пока не заработало.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от Begemoth

В RFC насано что для теста достаточно boobar в вариациях прогнать.

local base64
if tonumber(_VERSION:match('Lua 5.(%d+)')) <= 2 then
   base64 = require('5_1.base64')
else
   base64 = require('5_3.base64')
end
assert(base64.encode("") == "")
assert(base64.encode("f") == "Zg==",base64.encode("f"))
assert(base64.encode("fo") == "Zm8=",base64.encode("fo"))
assert(base64.encode("foo") == "Zm9v",base64.encode("foo"))
assert(base64.encode("foob") == "Zm9vYg==",base64.encode("foob"))
assert(base64.encode("fooba") == "Zm9vYmE=")
assert(base64.encode("foobar") == "Zm9vYmFy")
assert(base64.decode("") == "")
assert(base64.decode("Zg==")  == "f",base64.decode("Zg=="))
assert(base64.decode("Zm8=") == "fo",base64.decode("Zm8="))
assert(base64.decode("Zm9v") == "foo",base64.decode("Zm9v"))
assert(base64.decode("Zm9vYg==") == "foob",base64.decode("Zm9vYg=="))
assert(base64.decode("Zm9vYmE=") == "fooba",base64.decode("Zm9vYmE="))
assert(base64.decode("Zm9vYmFy") == "foobar",base64.decode("Zm9vYmFy"))

Этот локальный тест в README прописан. Почему не отдельным файлом? Не знаю.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от PPP328

У меня указан конкретный RFC да baseXYZ много всяких, я сначала хотел base64/32/53/URLencode и так далее комбайн. Но передумал, буду одно за другим отдельными штуками делать маленькими по пере надобности. Это интересно, практически применимо, а когда работает, приятно =)

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

baseXYZ много всяких

Да нет же. Самих base64 целое семейство

static const u8 rfc_map[BXI_BASE64_COUNT][BASE64_PAD + 1] = {
    /* BXI_BASE64_RFC1421  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
    /* BXI_BASE64_RFC2045  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
    /* BXI_BASE64_RFC3548  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
    /* BXI_BASE64_Y64      */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-",
    /* BXI_BASE64_XMLTOKEN */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-\0",
    /* BXI_BASE64_XMLNAME  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_:\0",
    /* BXI_BASE64_PIDENT1  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-\0",
    /* BXI_BASE64_PIDENT2  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._\0",
    /* BXI_BASE64_FREENET  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~-=",
    /* BXI_BASE64_RFC4880  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
    /* BXI_BASE64_RFC1642  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\0",
    /* BXI_BASE64_RFC3501  */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,\0"
};
PPP328 ★★★★★
()
Последнее исправление: PPP328 (всего исправлений: 1)
Ответ на: комментарий от PPP328

RFC4648 один. Другие семейства и то как в них что работает должно быть описано в других RFC или я что не понимаю?

Я ещё хотел добавить возможность указания своего алфавита для замены, но мне пока не нужно, а так на деле, новый арфавит или его размер вот тебе новый BaseЧтоТоТам. Во всех этих стандартах тупо меняется алфавит и битность индексации этого алфавита.

Что значит «семейство»? BaseЧтотоТам это насколько я видел всегда просто преобразование байт в индексы массива размера X который наполнен символами из набора Y, ну и обратное преобразование и всё. Что угодно поменяй, причём сделать это легко и вот тебе новый метод кодирования. Картинки из интернета, изображения в почте, утилита командной строки в твоём терминале всё RFC4648 по умолчанию. Ну, кажется так. В любом случае, я писал для себя, принимать картинки в виде base64 и сохранять как прост картинки, мои задачи решило и норм, а тут я просто выложил, как и всё иное. Если надо будет ещё какой то Base64 уникальный декодить, значит будем декодить тут как бы всё равно сколько их там этих семейств.

Можно ещё утилиту сделать которая будет определять в чём закодировано, можно на глаз, но не всегда это удобно.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

Те стандарты, что я выше перечислил в своём RFC говорят, мол "тут используется base64, но так как у нас есть ограничение на трансляцию конкретных символов, то там / меняется на ,, Жы на Хы, Пэ на Жэ и так далее. И мы получаем base64, описанный в другом RFC, имеющий другой набор байтов для конверсии.

PPP328 ★★★★★
()
Ответ на: комментарий от PPP328

Ааа, ну тогда идею с возможностью указать алфавит или имя RFC можно доделать, получится что-то вроде

  • base64.encode(data,'BASE64_XMLNAME')

или/и

  • base64.encode(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_:\0')

Попозже надо сделать. Как необязательный пареметр. Но лично мне пока не надо, может завтра.

LINUX-ORG-RU ★★★★★
() автор топика
Последнее исправление: LINUX-ORG-RU (всего исправлений: 3)
Ответ на: комментарий от LINUX-ORG-RU

А зачем вы используете битовые маски для конверсии? Многословно же получается. У нас в проекте вот так:

char * bxi_bin2base64(const bxi_bts * base64, bxi_base64_rfc rfc) {
    if (!base64 || rfc >= BXI_BASE64_COUNT)
        return NULL;

    u32 len = base64->size;
    char * out = bxi_malloc(BXI_STR2BASE64_OUT_SIZE(len));
    char * res = out;
    u8 * in = base64->data;

    while (len) {
        out[0] = rfc_map[rfc][in[0] >> 2];
        out[1] = rfc_map[rfc][((in[0] & 3) << 4) |
                (len > 1 ? (in[1] >> 4) : 0)];
        out[2] = len > 1 ? rfc_map[rfc][(((in[1] & 0xf) << 2) |
                (len > 2 ? (in[2] >> 6) : 0))] : rfc_map[rfc][BASE64_PAD];
        out[3] = len > 2 ? rfc_map[rfc][in[2] & 0x3f] : rfc_map[rfc][BASE64_PAD];

        out += BXI_BASE64_ENC_SIZE;
        in  += BXI_BASE64_DEC_SIZE;
        len -= BXI_MIN(BXI_BASE64_DEC_SIZE, len);
    }
    *out = '\0';

    return res;
}
PPP328 ★★★★★
()
Ответ на: комментарий от PPP328

Мне так удобнее мыслить, пошагово. Как придумал так и сделал. Я вообще сначала в тетрадочке нарисовал куда там что идёт, а уже потом в код вписал то что нарисовал в тетрадке. И то не сразу получалось. Чай не продакшон, а домашние поделочки.

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от PPP328

У тя вон тоже масочки, последний отктет отфильтровывать и байт и два бита так же как у меня, просто я их размазал и добавил там где они в целом и не нужны маски то. Лишние телодвижения есть у меня, но пусть так иначе спустя время я не раздуплю куда там и чего вообще :D

LINUX-ORG-RU ★★★★★
() автор топика
Ответ на: комментарий от dataman

Это будут путать с «я болею». Хотя тут люди приучатся к другому контексту и понесут его помиру :D Как 4.2 имя нарицательное уже

LINUX-ORG-RU ★★★★★
() автор топика
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от PPP328

Сел, сделал, жирно получается, ну там из за особенностей Lua посимвольная работа быстрая возможна только когда данные в таблице, но таблицу из 64 символов не удобно прописывать, поэтому нужно её генерировать из строки, какой именно алфавит кодирования будет выбран непонятно поэтому предварительно генерируются из строки в таблицу + обратная таблица для всех вариантов, это норм если модуль подгружается разово, но не норм если сделать CLI утилиту и лёргать её из вне в цикле, накладные расходы заметные на 1000 инициализаций модуля уходит 400миллисекунд, это дохрена почти пол секунды, полазал по RFC разным, там чёрт ногу сломит, тут мы этот символ заменим, там вот этот. Оставлю по умолчанию один RFC4648 с уже раскрытыми таблицами без накладных расходов, это главный Base64 в последней редакции (ну типа). Всё остальное его явные модификации из за тех или иных ограничений о чём во всех остальных RFC и говорится, есть некие ваще маргинальные вещи где алфавит тупо задом наперёд и так далее. Поэтому решил всё же не вшивать все RFC мира в код, а просто добавлю функцию base64_register(basename,alphabet,endcode) дабы любой треш включая лично свою модификацию под свои нужны можно было бы регать явно и в ридми добавлю описание таблиц трансляции тех о которых ты тут рассказал. Не знаю зачем я тут всё это расписываю, но спасибо ещё раз за инфу.

LINUX-ORG-RU ★★★★★
() автор топика