| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808 |
- /* qr.c Handles QR Code, Micro QR Code, UPNQR and rMQR */
- /*
- libzint - the open source barcode library
- Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com>
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the project nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- */
- /* SPDX-License-Identifier: BSD-3-Clause */
- #include <assert.h>
- #include <math.h>
- #include <stdio.h>
- #include "common.h"
- #include "eci.h"
- #include "qr.h"
- #include "reedsol.h"
- #define QR_ALPHA (IS_NUM_F | IS_UPR_F | IS_SPC_F | IS_AST_F | IS_PLS_F | IS_MNS_F | IS_SIL_F | IS_CLI_F)
- #define QR_LEVEL_L 0
- #define QR_LEVEL_M 1
- #define QR_LEVEL_Q 2
- #define QR_LEVEL_H 3
- static const char qr_ecc_level_names[] = { 'L', 'M', 'Q', 'H' };
- #define QR_PERCENT 38 /* Alphanumeric mode % */
- #define RMQR_VERSION 41
- #define MICROQR_VERSION 73
- /* Returns true if input glyph is in the Alphanumeric set or is GS1 FNC1 */
- static int qr_is_alpha(const unsigned int glyph, const int gs1) {
- if (is_chr(QR_ALPHA, glyph)) {
- return 1;
- }
- if (gs1 && glyph == '\x1D') {
- return 1;
- }
- return 0;
- }
- /* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
- #define QR_MULT 6
- /* Whether in numeric or not. If in numeric, *p_end is set to position after numeric, and *p_cost is set to
- * per-numeric cost */
- static int qr_in_numeric(const unsigned int ddata[], const int length, const int in_posn,
- unsigned int *p_end, unsigned int *p_cost) {
- int i, digit_cnt;
- if (in_posn < (int) *p_end) {
- return 1;
- }
- /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times QR_MULT) */
- for (i = in_posn; i < length && i < in_posn + 3 && z_isdigit(ddata[i]); i++);
- digit_cnt = i - in_posn;
- if (digit_cnt == 0) {
- *p_end = 0;
- return 0;
- }
- *p_end = i;
- *p_cost = digit_cnt == 1
- ? 24 /* 4 * QR_MULT */ : digit_cnt == 2 ? 21 /* (7 / 2) * QR_MULT */ : 20 /* (10 / 3) * QR_MULT) */;
- return 1;
- }
- /* Whether in alpha or not. If in alpha, *p_end is set to position after alpha, and *p_cost is set to per-alpha cost.
- * For GS1, *p_pcent set if 2nd char percent */
- static int qr_in_alpha(const unsigned int ddata[], const int length, const int in_posn,
- unsigned int *p_end, unsigned int *p_cost, unsigned int *p_pcent, unsigned int *p_pccnt,
- unsigned int gs1) {
- const int last = in_posn + 1 == length;
- int two_alphas;
- /* Attempt to calculate the average 'cost' of using alphanumeric mode in number of bits (times QR_MULT) */
- if (in_posn < (int) *p_end) {
- if (gs1) {
- if (*p_pcent) {
- /* Previous 2nd char was a percent, so allow for second half of doubled-up percent here */
- two_alphas = !last && qr_is_alpha(ddata[in_posn + 1], gs1);
- /* Uneven percents means this will fit evenly in alpha pair */
- *p_cost = two_alphas || !(*p_pccnt & 1) ? 66 /* 11 * QR_MULT */ : 69 /* (11 / 2 + 6) * QR_MULT */;
- *p_pcent = 0;
- } else {
- /* As above, uneven percents means will fit in alpha pair */
- *p_cost = !last || !(*p_pccnt & 1) ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
- }
- } else {
- *p_cost = !last ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
- }
- return 1;
- }
- if (!qr_is_alpha(ddata[in_posn], gs1)) {
- *p_end = 0;
- *p_pcent = 0;
- *p_pccnt = 0;
- return 0;
- }
- two_alphas = !last && qr_is_alpha(ddata[in_posn + 1], gs1);
- if (gs1 && ddata[in_posn] == '%') { /* Must double-up so counts as 2 chars */
- *p_end = in_posn + 1;
- *p_pcent = 0;
- (*p_pccnt)++;
- /* Uneven percents means will fit in alpha pair */
- *p_cost = two_alphas || !(*p_pccnt & 1) ? 66 /* 11 * QR_MULT */ : 69 /* (11 / 2 + 6) * QR_MULT */;
- return 1;
- }
- *p_end = two_alphas ? in_posn + 2 : in_posn + 1;
- if (gs1) {
- *p_pcent = two_alphas && ddata[in_posn + 1] == '%'; /* 2nd char is percent */
- *p_pccnt += *p_pcent;
- /* Uneven percents means will fit in alpha pair */
- *p_cost = two_alphas || !(*p_pccnt & 1) ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
- } else {
- *p_cost = two_alphas ? 33 /* (11 / 2) * QR_MULT */ : 36 /* 6 * QR_MULT */;
- }
- return 1;
- }
- #if 0
- #define QR_DEBUG_DEFINE_MODE /* For debugging costings */
- #endif
- /* Indexes into qr_mode_types array (and state array) */
- #define QR_N 0 /* Numeric */
- #define QR_A 1 /* Alphanumeric */
- #define QR_B 2 /* Byte */
- #define QR_K 3 /* Kanji */
- static const char qr_mode_types[] = { 'N', 'A', 'B', 'K', '\0' }; /* Must be in same order as QR_N etc */
- #define QR_NUM_MODES 4
- /* Indexes into state array (0..3 head costs) */
- #define QR_VER 4 /* Version */
- #define QR_N_END 5 /* Numeric end index */
- #define QR_N_COST 6 /* Numeric cost */
- #define QR_A_END 7 /* Alpha end index */
- #define QR_A_COST 8 /* Alpha cost */
- #define QR_A_PCENT 9 /* Alpha 2nd char percent (GS1-specific) */
- #define QR_A_PCCNT 10 /* Alpha total percent count (GS1-specific) */
- /* Costs set to this for invalid MICROQR modes for versions M1 and M2.
- * 128 is the max number of data bits for M4-L (ISO/IEC 18004:2015 Table 7) */
- #define QR_MICROQR_MAX 774 /* (128 + 1) * QR_MULT */
- /* Initial mode costs */
- static unsigned int *qr_head_costs(unsigned int state[11]) {
- static const unsigned int head_costs[7][QR_NUM_MODES] = {
- /* N A B K */
- { (10 + 4) * QR_MULT, (9 + 4) * QR_MULT, (8 + 4) * QR_MULT, (8 + 4) * QR_MULT, }, /* QR */
- { (12 + 4) * QR_MULT, (11 + 4) * QR_MULT, (16 + 4) * QR_MULT, (10 + 4) * QR_MULT, },
- { (14 + 4) * QR_MULT, (13 + 4) * QR_MULT, (16 + 4) * QR_MULT, (12 + 4) * QR_MULT, },
- { 3 * QR_MULT, QR_MICROQR_MAX, QR_MICROQR_MAX, QR_MICROQR_MAX, }, /* MICROQR */
- { (4 + 1) * QR_MULT, (3 + 1) * QR_MULT, QR_MICROQR_MAX, QR_MICROQR_MAX, },
- { (5 + 2) * QR_MULT, (4 + 2) * QR_MULT, (4 + 2) * QR_MULT, (3 + 2) * QR_MULT, },
- { (6 + 3) * QR_MULT, (5 + 3) * QR_MULT, (5 + 3) * QR_MULT, (4 + 3) * QR_MULT, }
- };
- int version;
- /* Head costs kept in states 0..3 */
- version = state[QR_VER];
- if (version < RMQR_VERSION) { /* QRCODE */
- if (version < 10) {
- memcpy(state, head_costs[0], QR_NUM_MODES * sizeof(unsigned int));
- } else if (version < 27) {
- memcpy(state, head_costs[1], QR_NUM_MODES * sizeof(unsigned int));
- } else {
- memcpy(state, head_costs[2], QR_NUM_MODES * sizeof(unsigned int));
- }
- } else if (version < MICROQR_VERSION) { /* RMQR */
- version -= RMQR_VERSION;
- state[QR_N] = (rmqr_numeric_cci[version] + 3) * QR_MULT;
- state[QR_A] = (rmqr_alphanum_cci[version] + 3) * QR_MULT;
- state[QR_B] = (rmqr_byte_cci[version] + 3) * QR_MULT;
- state[QR_K] = (rmqr_kanji_cci[version] + 3) * QR_MULT;
- } else { /* MICROQR */
- memcpy(state, head_costs[3 + (version - MICROQR_VERSION)], QR_NUM_MODES * sizeof(unsigned int));
- }
- return state;
- }
- /* Calculate optimized encoding modes. Adapted from Project Nayuki */
- static void qr_define_mode(char mode[], const unsigned int ddata[], const int length, const int gs1,
- const int version, const int debug_print) {
- /*
- * Copyright (c) Project Nayuki. (MIT License)
- * https://www.nayuki.io/page/qr-code-generator-library
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- * - The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
- unsigned int state[11] = {
- 0 /*N*/, 0 /*A*/, 0 /*B*/, 0 /*K*/, /* Head/switch costs */
- 0 /*version*/,
- 0 /*numeric_end*/, 0 /*numeric_cost*/, 0 /*alpha_end*/, 0 /*alpha_cost*/, 0 /*alpha_pcent*/, 0 /*alpha_pccnt*/
- };
- int m1, m2;
- int i, j, k;
- unsigned int min_cost;
- char cur_mode;
- unsigned int prev_costs[QR_NUM_MODES];
- unsigned int cur_costs[QR_NUM_MODES];
- char (*char_modes)[QR_NUM_MODES] = (char (*)[QR_NUM_MODES]) z_alloca(QR_NUM_MODES * length);
- state[QR_VER] = (unsigned int) version;
- /* char_modes[i][j] represents the mode to encode the code point at index i such that the final segment
- ends in qr_mode_types[j] and the total number of bits is minimized over all possible choices */
- memset(char_modes, 0, QR_NUM_MODES * length);
- /* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/QR_MULT)
- * bits needed to encode the entire string prefix of length i, and end in qr_mode_types[j] */
- memcpy(prev_costs, qr_head_costs(state), QR_NUM_MODES * sizeof(unsigned int));
- #ifdef QR_DEBUG_DEFINE_MODE
- printf(" head");
- for (j = 0; j < QR_NUM_MODES; j++) {
- printf(" %c(%c)=%d", qr_mode_types[j], char_modes[0][j], prev_costs[j]);
- }
- printf("\n");
- #endif
- /* Calculate costs using dynamic programming */
- for (i = 0; i < length; i++) {
- memset(cur_costs, 0, QR_NUM_MODES * sizeof(unsigned int));
- m1 = version == MICROQR_VERSION;
- m2 = version == MICROQR_VERSION + 1;
- if (ddata[i] > 0xFF) {
- cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 96); /* 16 * QR_MULT */
- char_modes[i][QR_B] = 'B';
- cur_costs[QR_K] = prev_costs[QR_K] + ((m1 || m2) ? QR_MICROQR_MAX : 78); /* 13 * QR_MULT */
- char_modes[i][QR_K] = 'K';
- } else {
- if (qr_in_numeric(ddata, length, i, &state[QR_N_END], &state[QR_N_COST])) {
- cur_costs[QR_N] = prev_costs[QR_N] + state[QR_N_COST];
- char_modes[i][QR_N] = 'N';
- }
- if (qr_in_alpha(ddata, length, i, &state[QR_A_END], &state[QR_A_COST], &state[QR_A_PCENT],
- &state[QR_A_PCCNT], gs1)) {
- cur_costs[QR_A] = prev_costs[QR_A] + (m1 ? QR_MICROQR_MAX : state[QR_A_COST]);
- char_modes[i][QR_A] = 'A';
- }
- cur_costs[QR_B] = prev_costs[QR_B] + ((m1 || m2) ? QR_MICROQR_MAX : 48); /* 8 * QR_MULT */
- char_modes[i][QR_B] = 'B';
- }
- /* Start new segment at the end to switch modes */
- for (j = 0; j < QR_NUM_MODES; j++) { /* To mode */
- for (k = 0; k < QR_NUM_MODES; k++) { /* From mode */
- if (j != k && char_modes[i][k]) {
- const unsigned int new_cost = cur_costs[k] + state[j]; /* Switch costs same as head costs */
- if (!char_modes[i][j] || new_cost < cur_costs[j]) {
- cur_costs[j] = new_cost;
- char_modes[i][j] = qr_mode_types[k];
- }
- }
- }
- }
- #ifdef QR_DEBUG_DEFINE_MODE
- {
- int min_j = 0;
- printf(" % 4d: curr", i);
- for (j = 0; j < QR_NUM_MODES; j++) {
- printf(" %c(%c)=%d", qr_mode_types[j], char_modes[i][j], cur_costs[j]);
- if (cur_costs[j] < cur_costs[min_j]) min_j = j;
- }
- printf(" min %c(%c)=%d\n", qr_mode_types[min_j], char_modes[i][min_j], cur_costs[min_j]);
- }
- #endif
- memcpy(prev_costs, cur_costs, QR_NUM_MODES * sizeof(unsigned int));
- }
- /* Find optimal ending mode */
- min_cost = prev_costs[0];
- cur_mode = qr_mode_types[0];
- for (i = 1; i < QR_NUM_MODES; i++) {
- if (prev_costs[i] < min_cost) {
- min_cost = prev_costs[i];
- cur_mode = qr_mode_types[i];
- }
- }
- /* Get optimal mode for each code point by tracing backwards */
- for (i = length - 1; i >= 0; i--) {
- j = posn(qr_mode_types, cur_mode);
- cur_mode = char_modes[i][j];
- mode[i] = cur_mode;
- }
- if (debug_print) {
- printf(" Mode: %.*s\n", length, mode);
- }
- }
- /* Returns mode indicator based on version and mode */
- static int qr_mode_indicator(const int version, const int mode) {
- static const char mode_indicators[6][QR_NUM_MODES] = {
- /*N A B K */
- { 1, 2, 4, 8, }, /* QRCODE */
- { 1, 2, 3, 4, }, /* RMQR */
- { 0, 0, 0, 0, }, /* MICROQR */
- { 0, 1, 0, 0, },
- { 0, 1, 2, 3, },
- { 0, 1, 2, 3, },
- };
- int mode_index = posn(qr_mode_types, (const char) mode);
- if (version < RMQR_VERSION) {
- return mode_indicators[0][mode_index]; /* QRCODE */
- }
- if (version < MICROQR_VERSION) {
- return mode_indicators[1][mode_index] /* RMQR */;
- }
- return mode_indicators[2 + version - MICROQR_VERSION][mode_index]; /* MICROQR */
- }
- /* Return mode indicator bits based on version */
- static int qr_mode_bits(const int version) {
- if (version < RMQR_VERSION) {
- return 4; /* QRCODE */
- }
- if (version < MICROQR_VERSION) {
- return 3; /* RMQR */
- }
- return version - MICROQR_VERSION; /* MICROQR */
- }
- /* Return character count indicator bits based on version and mode */
- static int qr_cci_bits(const int version, const int mode) {
- static const char cci_bits[7][QR_NUM_MODES] = {
- /* N A B K */
- { 10, 9, 8, 8, }, /* QRCODE */
- { 12, 11, 16, 10, },
- { 14, 13, 16, 12, },
- { 3, 0, 0, 0, }, /* MICROQR */
- { 4, 3, 0, 0, },
- { 5, 4, 4, 3, },
- { 6, 5, 5, 4, }
- };
- static const unsigned char *const rmqr_ccis[QR_NUM_MODES] = {
- rmqr_numeric_cci, rmqr_alphanum_cci, rmqr_byte_cci, rmqr_kanji_cci,
- };
- int mode_index = posn(qr_mode_types, (const char) mode);
- if (version < RMQR_VERSION) { /* QRCODE */
- if (version < 10) {
- return cci_bits[0][mode_index];
- }
- if (version < 27) {
- return cci_bits[1][mode_index];
- }
- return cci_bits[2][mode_index];
- }
- if (version < MICROQR_VERSION) { /* RMQR */
- return rmqr_ccis[mode_index][version - RMQR_VERSION];
- }
- return cci_bits[3 + (version - MICROQR_VERSION)][mode_index]; /* MICROQR */
- }
- /* Returns terminator bits based on version */
- static int qr_terminator_bits(const int version) {
- if (version < RMQR_VERSION) {
- return 4; /* QRCODE */
- }
- if (version < MICROQR_VERSION) {
- return 3; /* RMQR */
- }
- return 3 + (version - MICROQR_VERSION) * 2; /* MICROQR */
- }
- /* Convert input data to a binary stream and add padding */
- static int qr_binary(char binary[], int bp, const int version, const char mode[],
- const unsigned int ddata[], const int length, const int gs1,
- const int eci, const int debug_print) {
- int position = 0;
- int i;
- int modebits;
- int percent = 0;
- int percent_count;
- if (eci != 0) { /* Not applicable to MICROQR */
- bp = bin_append_posn(7, version < RMQR_VERSION ? 4 : 3, binary, bp); /* ECI (Table 4) */
- if (eci <= 127) {
- bp = bin_append_posn(eci, 8, binary, bp); /* 000000 to 000127 */
- } else if (eci <= 16383) {
- bp = bin_append_posn(0x8000 + eci, 16, binary, bp); /* 000128 to 016383 */
- } else {
- bp = bin_append_posn(0xC00000 + eci, 24, binary, bp); /* 016384 to 999999 */
- }
- }
- modebits = qr_mode_bits(version);
- do {
- char data_block = mode[position];
- int short_data_block_length = 0;
- int double_byte = 0;
- do {
- if (data_block == 'B' && ddata[position + short_data_block_length] > 0xFF) {
- double_byte++;
- }
- short_data_block_length++;
- } while (((short_data_block_length + position) < length)
- && (mode[position + short_data_block_length] == data_block));
- /* Mode indicator */
- if (modebits) {
- bp = bin_append_posn(qr_mode_indicator(version, data_block), modebits, binary, bp);
- }
- switch (data_block) {
- case 'K':
- /* Kanji mode */
- /* Character count indicator */
- bp = bin_append_posn(short_data_block_length, qr_cci_bits(version, data_block), binary, bp);
- if (debug_print) {
- printf("Kanji block (length %d)\n\t", short_data_block_length);
- }
- /* Character representation */
- for (i = 0; i < short_data_block_length; i++) {
- unsigned int jis = ddata[position + i];
- int prod;
- if (jis >= 0x8140 && jis <= 0x9ffc)
- jis -= 0x8140;
- else if (jis >= 0xe040 && jis <= 0xebbf)
- jis -= 0xc140;
- prod = ((jis >> 8) * 0xc0) + (jis & 0xff);
- bp = bin_append_posn(prod, 13, binary, bp);
- if (debug_print) {
- printf("0x%04X ", prod);
- }
- }
- if (debug_print) {
- fputc('\n', stdout);
- }
- break;
- case 'B':
- /* Byte mode */
- /* Character count indicator */
- bp = bin_append_posn(short_data_block_length + double_byte, qr_cci_bits(version, data_block), binary,
- bp);
- if (debug_print) {
- printf("Byte block (length %d)\n\t", short_data_block_length + double_byte);
- }
- /* Character representation */
- for (i = 0; i < short_data_block_length; i++) {
- unsigned int byte = ddata[position + i];
- bp = bin_append_posn(byte, byte > 0xFF ? 16 : 8, binary, bp);
- if (debug_print) {
- printf("0x%02X(%d) ", byte, (int) byte);
- }
- }
- if (debug_print) {
- fputc('\n', stdout);
- }
- break;
- case 'A':
- /* Alphanumeric mode */
- percent_count = 0;
- if (gs1) {
- for (i = 0; i < short_data_block_length; i++) {
- if (ddata[position + i] == '%') {
- percent_count++;
- }
- }
- }
- /* Character count indicator */
- bp = bin_append_posn(short_data_block_length + percent_count, qr_cci_bits(version, data_block),
- binary, bp);
- if (debug_print) {
- printf("Alpha block (length %d)\n\t", short_data_block_length + percent_count);
- }
- /* Character representation */
- i = 0;
- while (i < short_data_block_length) {
- int count;
- int first = 0, second = 0, prod;
- if (percent == 0) {
- if (gs1 && (ddata[position + i] == '%')) {
- first = QR_PERCENT;
- second = QR_PERCENT;
- count = 2;
- prod = (first * 45) + second;
- i++;
- } else {
- if (gs1 && ddata[position + i] == '\x1D') {
- first = QR_PERCENT; /* FNC1 */
- } else {
- first = qr_alphanumeric[ddata[position + i] - 32];
- }
- count = 1;
- i++;
- prod = first;
- if (i < short_data_block_length && mode[position + i] == 'A') {
- if (gs1 && (ddata[position + i] == '%')) {
- second = QR_PERCENT;
- count = 2;
- prod = (first * 45) + second;
- percent = 1;
- } else {
- if (gs1 && ddata[position + i] == '\x1D') {
- second = QR_PERCENT; /* FNC1 */
- } else {
- second = qr_alphanumeric[ddata[position + i] - 32];
- }
- count = 2;
- i++;
- prod = (first * 45) + second;
- }
- }
- }
- } else {
- first = QR_PERCENT;
- count = 1;
- i++;
- prod = first;
- percent = 0;
- if (i < short_data_block_length && mode[position + i] == 'A') {
- if (gs1 && (ddata[position + i] == '%')) {
- second = QR_PERCENT;
- count = 2;
- prod = (first * 45) + second;
- percent = 1;
- } else {
- if (gs1 && ddata[position + i] == '\x1D') {
- second = QR_PERCENT; /* FNC1 */
- } else {
- second = qr_alphanumeric[ddata[position + i] - 32];
- }
- count = 2;
- i++;
- prod = (first * 45) + second;
- }
- }
- }
- bp = bin_append_posn(prod, 1 + (5 * count), binary, bp);
- if (debug_print) {
- printf("0x%X ", prod);
- }
- }
- if (debug_print) {
- fputc('\n', stdout);
- }
- break;
- case 'N':
- /* Numeric mode */
- /* Character count indicator */
- bp = bin_append_posn(short_data_block_length, qr_cci_bits(version, data_block), binary, bp);
- if (debug_print) {
- printf("Number block (length %d)\n\t", short_data_block_length);
- }
- /* Character representation */
- i = 0;
- while (i < short_data_block_length) {
- int count;
- int first = 0, prod;
- first = ctoi((const char) ddata[position + i]);
- count = 1;
- prod = first;
- if (i + 1 < short_data_block_length && mode[position + i + 1] == 'N') {
- int second = ctoi((const char) ddata[position + i + 1]);
- count = 2;
- prod = (prod * 10) + second;
- if (i + 2 < short_data_block_length && mode[position + i + 2] == 'N') {
- int third = ctoi((const char) ddata[position + i + 2]);
- count = 3;
- prod = (prod * 10) + third;
- }
- }
- bp = bin_append_posn(prod, 1 + (3 * count), binary, bp);
- if (debug_print) {
- printf("0x%X(%d) ", prod, prod);
- }
- i += count;
- };
- if (debug_print) {
- fputc('\n', stdout);
- }
- break;
- }
- position += short_data_block_length;
- } while (position < length);
- return bp;
- }
- /* Call `qr_binary()` for each segment, dealing with Structured Append and GS1 beforehand and padding afterwards */
- static int qr_binary_segs(unsigned char datastream[], const int version, const int target_codewords,
- const char mode[], const unsigned int ddata[], const struct zint_seg segs[], const int seg_count,
- const struct zint_structapp *p_structapp, const int gs1, const int est_binlen, const int debug_print) {
- int i, j;
- const unsigned int *dd = ddata;
- const char *m = mode;
- int bp = 0;
- int termbits, padbits;
- int current_bytes;
- int toggle;
- char *binary = (char *) z_alloca(est_binlen + 12);
- *binary = '\0';
- if (p_structapp) {
- bp = bin_append_posn(3, 4, binary, bp); /* Structured Append indicator */
- bp = bin_append_posn(p_structapp->index - 1, 4, binary, bp);
- bp = bin_append_posn(p_structapp->count - 1, 4, binary, bp);
- bp = bin_append_posn(to_int((const unsigned char *) p_structapp->id, (int) strlen(p_structapp->id)), 8,
- binary, bp); /* Parity */
- }
- if (gs1) { /* Not applicable to MICROQR */
- if (version < RMQR_VERSION) {
- bp = bin_append_posn(5, 4, binary, bp); /* FNC1 */
- } else {
- bp = bin_append_posn(5, 3, binary, bp);
- }
- }
- for (i = 0; i < seg_count; i++) {
- bp = qr_binary(binary, bp, version, m, dd, segs[i].length, gs1, segs[i].eci, debug_print);
- m += segs[i].length;
- dd += segs[i].length;
- }
- if (version >= MICROQR_VERSION && version < MICROQR_VERSION + 4) {
- /* MICROQR does its own terminating/padding */
- memcpy(datastream, binary, bp);
- return bp;
- }
- /* Terminator */
- termbits = 8 - bp % 8;
- if (termbits == 8) {
- termbits = 0;
- }
- current_bytes = (bp + termbits) / 8;
- if (termbits || current_bytes < target_codewords) {
- int max_termbits = qr_terminator_bits(version);
- termbits = termbits < max_termbits && current_bytes == target_codewords ? termbits : max_termbits;
- bp = bin_append_posn(0, termbits, binary, bp);
- }
- /* Padding bits */
- padbits = 8 - bp % 8;
- if (padbits == 8) {
- padbits = 0;
- }
- if (padbits) {
- current_bytes = (bp + padbits) / 8;
- (void) bin_append_posn(0, padbits, binary, bp); /* Last use so not setting bp */
- }
- if (debug_print) printf("Terminated binary (%d): %.*s (padbits %d)\n", bp, bp, binary, padbits);
- /* Put data into 8-bit codewords */
- for (i = 0; i < current_bytes; i++) {
- int p;
- j = i * 8;
- datastream[i] = 0x00;
- for (p = 0; p < 8; p++) {
- if (binary[j + p] == '1') {
- datastream[i] |= (0x80 >> p);
- }
- }
- }
- /* Add pad codewords */
- toggle = 0;
- for (i = current_bytes; i < target_codewords; i++) {
- if (toggle == 0) {
- datastream[i] = 0xec;
- toggle = 1;
- } else {
- datastream[i] = 0x11;
- toggle = 0;
- }
- }
- if (debug_print) {
- printf("Resulting codewords (%d):\n\t", target_codewords);
- for (i = 0; i < target_codewords; i++) {
- printf("0x%02X ", datastream[i]);
- }
- fputc('\n', stdout);
- }
- return 0; /* Not used */
- }
- /* Split data into blocks, add error correction and then interleave the blocks and error correction data */
- static void qr_add_ecc(unsigned char fullstream[], const unsigned char datastream[], const int version,
- const int data_cw, const int blocks, const int debug_print) {
- int ecc_cw;
- int short_data_block_length;
- int qty_long_blocks;
- int qty_short_blocks;
- int ecc_block_length;
- int i, j, length_this_block, in_posn;
- rs_t rs;
- unsigned char *data_block;
- unsigned char *ecc_block;
- unsigned char *interleaved_data;
- unsigned char *interleaved_ecc;
- if (version < RMQR_VERSION) {
- ecc_cw = qr_total_codewords[version - 1] - data_cw;
- } else {
- ecc_cw = rmqr_total_codewords[version - RMQR_VERSION] - data_cw;
- }
- /* Suppress some clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.Assign warnings */
- assert(blocks > 0);
- short_data_block_length = data_cw / blocks;
- qty_long_blocks = data_cw % blocks;
- qty_short_blocks = blocks - qty_long_blocks;
- ecc_block_length = ecc_cw / blocks;
- /* Suppress some clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.Assign warnings */
- assert(short_data_block_length > 0);
- assert(qty_long_blocks || qty_short_blocks);
- data_block = (unsigned char *) z_alloca(short_data_block_length + 1);
- ecc_block = (unsigned char *) z_alloca(ecc_block_length);
- interleaved_data = (unsigned char *) z_alloca(data_cw);
- interleaved_ecc = (unsigned char *) z_alloca(ecc_cw);
- rs_init_gf(&rs, 0x11d);
- rs_init_code(&rs, ecc_block_length, 0);
- in_posn = 0;
- for (i = 0; i < blocks; i++) {
- if (i < qty_short_blocks) {
- length_this_block = short_data_block_length;
- } else {
- length_this_block = short_data_block_length + 1;
- }
- for (j = 0; j < length_this_block; j++) {
- /* This false-positive popped up with clang-tidy 14.0.1 */
- data_block[j] = datastream[in_posn + j]; /* NOLINT(clang-analyzer-core.uninitialized.Assign) */
- }
- rs_encode(&rs, length_this_block, data_block, ecc_block);
- if (debug_print) {
- printf("Block %d: ", i + 1);
- for (j = 0; j < length_this_block; j++) {
- printf("%2X ", data_block[j]);
- }
- if (i < qty_short_blocks) {
- fputs(" ", stdout);
- }
- fputs(" // ", stdout);
- for (j = 0; j < ecc_block_length; j++) {
- printf("%2X ", ecc_block[j]);
- }
- fputc('\n', stdout);
- }
- for (j = 0; j < short_data_block_length; j++) {
- /* And another with clang-tidy 14.0.6 */
- interleaved_data[(j * blocks) + i] = data_block[j]; /* NOLINT(clang-analyzer-core.uninitialized.Assign) */
- }
- if (i >= qty_short_blocks) {
- interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)]
- = data_block[short_data_block_length];
- }
- for (j = 0; j < ecc_block_length; j++) {
- interleaved_ecc[(j * blocks) + i] = ecc_block[j];
- }
- in_posn += length_this_block;
- }
- for (j = 0; j < data_cw; j++) {
- fullstream[j] = interleaved_data[j];
- }
- for (j = 0; j < ecc_cw; j++) {
- fullstream[j + data_cw] = interleaved_ecc[j];
- }
- if (debug_print) {
- printf("\nData Stream (%d): \n", data_cw + ecc_cw);
- for (j = 0; j < (data_cw + ecc_cw); j++) {
- printf("%2X ", fullstream[j]);
- }
- fputc('\n', stdout);
- }
- }
- static void qr_place_finder(unsigned char grid[], const int size, const int x, const int y) {
- int xp, yp;
- char finder[] = {0x7F, 0x41, 0x5D, 0x5D, 0x5D, 0x41, 0x7F};
- for (xp = 0; xp < 7; xp++) {
- for (yp = 0; yp < 7; yp++) {
- if (finder[yp] & 0x40 >> xp) {
- grid[((yp + y) * size) + (xp + x)] = 0x11;
- } else {
- grid[((yp + y) * size) + (xp + x)] = 0x10;
- }
- }
- }
- }
- static void qr_place_align(unsigned char grid[], const int size, int x, int y) {
- int xp, yp;
- char alignment[] = {0x1F, 0x11, 0x15, 0x11, 0x1F};
- x -= 2;
- y -= 2; /* Input values represent centre of pattern */
- for (xp = 0; xp < 5; xp++) {
- for (yp = 0; yp < 5; yp++) {
- if (alignment[yp] & 0x10 >> xp) {
- grid[((yp + y) * size) + (xp + x)] = 0x11;
- } else {
- grid[((yp + y) * size) + (xp + x)] = 0x10;
- }
- }
- }
- }
- static void qr_setup_grid(unsigned char *grid, const int size, const int version) {
- int i, toggle = 1;
- /* Suppress false positive gcc >= 13 warning (when optimizing only) "writing 1 byte into a region of size 0" */
- #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 13
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wstringop-overflow"
- #endif
- /* Add timing patterns */
- for (i = 0; i < size; i++) {
- if (toggle == 1) {
- grid[(6 * size) + i] = 0x21;
- grid[(i * size) + 6] = 0x21;
- toggle = 0;
- } else {
- grid[(6 * size) + i] = 0x20;
- grid[(i * size) + 6] = 0x20;
- toggle = 1;
- }
- }
- /* Add finder patterns */
- qr_place_finder(grid, size, 0, 0);
- qr_place_finder(grid, size, 0, size - 7);
- qr_place_finder(grid, size, size - 7, 0);
- /* Add separators */
- for (i = 0; i < 7; i++) {
- grid[(7 * size) + i] = 0x10;
- grid[(i * size) + 7] = 0x10;
- grid[(7 * size) + (size - 1 - i)] = 0x10;
- grid[(i * size) + (size - 8)] = 0x10;
- grid[((size - 8) * size) + i] = 0x10;
- grid[((size - 1 - i) * size) + 7] = 0x10;
- }
- grid[(7 * size) + 7] = 0x10;
- grid[(7 * size) + (size - 8)] = 0x10;
- grid[((size - 8) * size) + 7] = 0x10;
- #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 13
- #pragma GCC diagnostic pop
- #endif
- /* Add alignment patterns */
- if (version != 1) {
- /* Version 1 does not have alignment patterns */
- int loopsize = qr_align_loopsize[version - 1];
- int x, y;
- for (x = 0; x < loopsize; x++) {
- for (y = 0; y < loopsize; y++) {
- int xcoord = qr_table_e1[((version - 2) * 7) + x];
- int ycoord = qr_table_e1[((version - 2) * 7) + y];
- if (!(grid[(ycoord * size) + xcoord] & 0x10)) {
- qr_place_align(grid, size, xcoord, ycoord);
- }
- }
- }
- }
- /* Reserve space for format information */
- for (i = 0; i < 8; i++) {
- grid[(8 * size) + i] |= 0x20;
- grid[(i * size) + 8] |= 0x20;
- grid[(8 * size) + (size - 1 - i)] = 0x20;
- grid[((size - 1 - i) * size) + 8] = 0x20;
- }
- grid[(8 * size) + 8] |= 0x20;
- grid[((size - 1 - 7) * size) + 8] = 0x21; /* Dark Module from Figure 25 */
- /* Reserve space for version information */
- if (version >= 7) {
- for (i = 0; i < 6; i++) {
- grid[((size - 9) * size) + i] = 0x20;
- grid[((size - 10) * size) + i] = 0x20;
- grid[((size - 11) * size) + i] = 0x20;
- grid[(i * size) + (size - 9)] = 0x20;
- grid[(i * size) + (size - 10)] = 0x20;
- grid[(i * size) + (size - 11)] = 0x20;
- }
- }
- }
- static int qr_cwbit(const unsigned char *fullstream, const int i) {
- if (fullstream[(i >> 3)] & (0x80 >> (i & 0x07))) {
- return 1;
- }
- return 0;
- }
- static void qr_populate_grid(unsigned char *grid, const int h_size, const int v_size, const unsigned char *fullstream,
- const int cw) {
- const int not_rmqr = v_size == h_size;
- const int x_start = h_size - (not_rmqr ? 2 : 3); /* For rMQR allow for righthand vertical timing pattern */
- int direction = 1; /* up */
- int row = 0; /* right hand side */
- int i, n, y;
- n = cw * 8;
- y = v_size - 1;
- i = 0;
- while (i < n) {
- int x = x_start - (row * 2);
- int r = y * h_size;
- if ((x < 6) && (not_rmqr))
- x--; /* skip over vertical timing pattern */
- if (!(grid[r + (x + 1)] & 0xf0)) {
- grid[r + (x + 1)] = qr_cwbit(fullstream, i);
- i++;
- }
- if (i < n) {
- if (!(grid[r + x] & 0xf0)) {
- grid[r + x] = qr_cwbit(fullstream, i);
- i++;
- }
- }
- if (direction) {
- y--;
- if (y == -1) {
- /* reached the top */
- row++;
- y = 0;
- direction = 0;
- }
- } else {
- y++;
- if (y == v_size) {
- /* reached the bottom */
- row++;
- y = v_size - 1;
- direction = 1;
- }
- }
- }
- }
- #ifdef ZINTLOG
- static void append_log(const unsigned char log) {
- FILE *file;
- if ((file = fopen("zintlog.txt", "a+"))) {
- fprintf(file, "%02X", log);
- (void) fclose(file);
- }
- }
- static void write_log(const char log[]) {
- FILE *file;
- if ((file = fopen("zintlog.txt", "a+"))) {
- fprintf(file, "%s\n", log); /*writes*/
- (void) fclose(file);
- }
- }
- #endif
- static int qr_evaluate(unsigned char *local, const int size) {
- static const unsigned char h1011101[7] = { 1, 0, 1, 1, 1, 0, 1 };
- int x, y, r, k, block;
- int result = 0;
- char state;
- int dark_mods;
- double percentage;
- int a, b, afterCount, beforeCount;
- #ifdef ZINTLOG
- int result_b = 0;
- char str[15];
- #endif
- /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult warnings */
- assert(size > 0);
- #ifdef ZINTLOG
- /* bitmask output */
- for (y = 0; y < size; y++) {
- for (x = 0; x < size; x++) {
- append_log(local[(y * size) + x]);
- }
- write_log("");
- }
- #endif
- /* Test 1: Adjacent modules in row/column in same colour */
- /* Vertical */
- for (x = 0; x < size; x++) {
- block = 0;
- state = 0;
- for (y = 0; y < size; y++) {
- if (local[(y * size) + x] == state) {
- block++;
- } else {
- if (block >= 5) {
- result += block - 2;
- }
- block = 1;
- state = local[(y * size) + x];
- }
- }
- if (block >= 5) {
- result += block - 2;
- }
- }
- /* Horizontal */
- dark_mods = 0; /* Count dark mods simultaneously (see Test 4 below) */
- for (y = 0; y < size; y++) {
- r = y * size;
- block = 0;
- state = 0;
- for (x = 0; x < size; x++) {
- if (local[r + x] == state) {
- block++;
- } else {
- if (block >= 5) {
- result += block - 2;
- }
- block = 1;
- state = local[r + x];
- }
- if (state) {
- dark_mods++;
- }
- }
- if (block >= 5) {
- result += block - 2;
- }
- }
- #ifdef ZINTLOG
- /* output Test 1 */
- sprintf(str, "%d", result);
- result_b = result;
- write_log(str);
- #endif
- /* Test 2: Block of modules in same color */
- for (x = 0; x < size - 1; x++) {
- for (y = 0; y < size - 1; y++) {
- k = local[(y * size) + x];
- if (((k == local[((y + 1) * size) + x]) &&
- (k == local[(y * size) + (x + 1)])) &&
- (k == local[((y + 1) * size) + (x + 1)])) {
- result += 3;
- }
- }
- }
- #ifdef ZINTLOG
- /* output Test 2 */
- sprintf(str, "%d", result - result_b);
- result_b = result;
- write_log(str);
- #endif
- /* Test 3: 1:1:3:1:1 ratio pattern in row/column */
- /* Vertical */
- for (x = 0; x < size; x++) {
- for (y = 0; y <= (size - 7); y++) {
- if (local[y * size + x] && !local[(y + 1) * size + x] && local[(y + 2) * size + x] &&
- local[(y + 3) * size + x] && local[(y + 4) * size + x] &&
- !local[(y + 5) * size + x] && local[(y + 6) * size + x]) {
- /* Pattern found, check before and after */
- beforeCount = 0;
- for (b = (y - 1); b >= (y - 4); b--) {
- if (b < 0) { /* Count < edge as whitespace */
- beforeCount = 4;
- break;
- }
- if (local[(b * size) + x]) {
- break;
- }
- beforeCount++;
- }
- if (beforeCount == 4) {
- /* Pattern is preceded by light area 4 modules wide */
- result += 40;
- } else {
- afterCount = 0;
- for (a = (y + 7); a <= (y + 10); a++) {
- if (a >= size) { /* Count > edge as whitespace */
- afterCount = 4;
- break;
- }
- if (local[(a * size) + x]) {
- break;
- }
- afterCount++;
- }
- if (afterCount == 4) {
- /* Pattern is followed by light area 4 modules wide */
- result += 40;
- }
- }
- y += 3; /* Skip to next possible match */
- }
- }
- }
- /* Horizontal */
- for (y = 0; y < size; y++) {
- r = y * size;
- for (x = 0; x <= (size - 7); x++) {
- if (memcmp(local + r + x, h1011101, 7) == 0) {
- /* Pattern found, check before and after */
- beforeCount = 0;
- for (b = (x - 1); b >= (x - 4); b--) {
- if (b < 0) { /* Count < edge as whitespace */
- beforeCount = 4;
- break;
- }
- if (local[r + b]) {
- break;
- }
- beforeCount++;
- }
- if (beforeCount == 4) {
- /* Pattern is preceded by light area 4 modules wide */
- result += 40;
- } else {
- afterCount = 0;
- for (a = (x + 7); a <= (x + 10); a++) {
- if (a >= size) { /* Count > edge as whitespace */
- afterCount = 4;
- break;
- }
- if (local[r + a]) {
- break;
- }
- afterCount++;
- }
- if (afterCount == 4) {
- /* Pattern is followed by light area 4 modules wide */
- result += 40;
- }
- }
- x += 3; /* Skip to next possible match */
- }
- }
- }
- #ifdef ZINTLOG
- /* output Test 3 */
- sprintf(str, "%d", result - result_b);
- result_b = result;
- write_log(str);
- #endif
- /* Test 4: Proportion of dark modules in entire symbol */
- percentage = (100.0 * dark_mods) / (size * size);
- k = (int) (fabs(percentage - 50.0) / 5.0);
- result += 10 * k;
- #ifdef ZINTLOG
- /* output Test 4+summary */
- sprintf(str, "%d", result - result_b);
- write_log(str);
- write_log("==========");
- sprintf(str, "%d", result);
- write_log(str);
- #endif
- return result;
- }
- /* Add format information to grid */
- static void qr_add_format_info(unsigned char *grid, const int size, const int ecc_level, const int pattern) {
- int format = pattern;
- unsigned int seq;
- int i;
- switch (ecc_level) {
- case QR_LEVEL_L: format |= 0x08;
- break;
- case QR_LEVEL_Q: format |= 0x18;
- break;
- case QR_LEVEL_H: format |= 0x10;
- break;
- }
- seq = qr_annex_c[format];
- for (i = 0; i < 6; i++) {
- grid[(i * size) + 8] |= (seq >> i) & 0x01;
- }
- for (i = 0; i < 8; i++) {
- grid[(8 * size) + (size - i - 1)] |= (seq >> i) & 0x01;
- }
- for (i = 0; i < 6; i++) {
- grid[(8 * size) + (5 - i)] |= (seq >> (i + 9)) & 0x01;
- }
- for (i = 0; i < 7; i++) {
- grid[(((size - 7) + i) * size) + 8] |= (seq >> (i + 8)) & 0x01;
- }
- grid[(7 * size) + 8] |= (seq >> 6) & 0x01;
- grid[(8 * size) + 8] |= (seq >> 7) & 0x01;
- grid[(8 * size) + 7] |= (seq >> 8) & 0x01;
- }
- static int qr_apply_bitmask(unsigned char *grid, const int size, const int ecc_level, const int user_mask,
- const int fast_encode, const int debug_print) {
- int x, y;
- int r, k;
- int bit;
- int pattern, penalty[8];
- int best_pattern;
- int size_squared = size * size;
- unsigned char *mask = (unsigned char *) z_alloca(size_squared);
- unsigned char *local = (unsigned char *) z_alloca(size_squared);
- #ifdef ZINTLOG
- char str[15];
- #endif
- /* Perform data masking */
- memset(mask, 0, size_squared);
- for (y = 0; y < size; y++) {
- r = y * size;
- for (x = 0; x < size; x++) {
- /* all eight bitmask variants are encoded in the 8 bits of the bytes that make up the mask array. */
- if (!(grid[r + x] & 0xf0)) { /* exclude areas not to be masked. */
- if (((y + x) & 1) == 0) {
- mask[r + x] |= 0x01;
- }
- if (!fast_encode) {
- if ((y & 1) == 0) {
- mask[r + x] |= 0x02;
- }
- }
- if ((x % 3) == 0) {
- mask[r + x] |= 0x04;
- }
- if (!fast_encode) {
- if (((y + x) % 3) == 0) {
- mask[r + x] |= 0x08;
- }
- }
- if ((((y / 2) + (x / 3)) & 1) == 0) {
- mask[r + x] |= 0x10;
- }
- if (!fast_encode) {
- if ((y * x) % 6 == 0) { /* Equivalent to (y * x) % 2 + (y * x) % 3 == 0 */
- mask[r + x] |= 0x20;
- }
- if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) {
- mask[r + x] |= 0x40;
- }
- }
- if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) {
- mask[r + x] |= 0x80;
- }
- }
- }
- }
- if (user_mask) {
- best_pattern = user_mask - 1;
- } else {
- /* all eight bitmask variants have been encoded in the 8 bits of the bytes
- * that make up the mask array. select them for evaluation according to the
- * desired pattern.*/
- best_pattern = 0;
- for (pattern = 0; pattern < 8; pattern++) {
- if (fast_encode && pattern != 0 && pattern != 2 && pattern != 4 && pattern != 7) {
- continue;
- }
- bit = 1 << pattern;
- for (k = 0; k < size_squared; k++) {
- if (mask[k] & bit) {
- local[k] = grid[k] ^ 0x01;
- } else {
- local[k] = grid[k] & 0x0f;
- }
- }
- qr_add_format_info(local, size, ecc_level, pattern);
- penalty[pattern] = qr_evaluate(local, size);
- if (penalty[pattern] < penalty[best_pattern]) {
- best_pattern = pattern;
- }
- }
- }
- if (debug_print) {
- printf("Mask: %d (%s)", best_pattern, user_mask ? "specified" : fast_encode ? "fast automatic": "automatic");
- if (!user_mask) {
- if (fast_encode) {
- printf(" 0:%d 2:%d 4:%d 7:%d", penalty[0], penalty[2], penalty[4], penalty[7]);
- } else {
- for (pattern = 0; pattern < 8; pattern++) printf(" %d:%d", pattern, penalty[pattern]);
- }
- }
- fputc('\n', stdout);
- }
- #ifdef ZINTLOG
- sprintf(str, "%d", best_pattern);
- write_log("chose pattern:");
- write_log(str);
- #endif
- /* Apply mask */
- if (!user_mask && best_pattern == 7) { /* Reuse last */
- memcpy(grid, local, size_squared);
- } else {
- bit = 1 << best_pattern;
- for (y = 0; y < size_squared; y++) {
- if (mask[y] & bit) {
- grid[y] ^= 0x01;
- }
- }
- }
- return best_pattern;
- }
- /* Add version information */
- static void qr_add_version_info(unsigned char *grid, const int size, const int version) {
- int i;
- unsigned int version_data = qr_annex_d[version - 7];
- for (i = 0; i < 6; i++) {
- grid[((size - 11) * size) + i] |= (version_data >> (i * 3)) & 1;
- grid[((size - 10) * size) + i] |= (version_data >> ((i * 3) + 1)) & 1;
- grid[((size - 9) * size) + i] |= (version_data >> ((i * 3) + 2)) & 1;
- grid[(i * size) + (size - 11)] |= (version_data >> (i * 3)) & 1;
- grid[(i * size) + (size - 10)] |= (version_data >> ((i * 3) + 1)) & 1;
- grid[(i * size) + (size - 9)] |= (version_data >> ((i * 3) + 2)) & 1;
- }
- }
- /* Find the length of the block starting from 'start' */
- static int qr_blockLength(const int start, const char mode[], const int length) {
- int i;
- int count = 0;
- char start_mode = mode[start];
- i = start;
- do {
- count++;
- } while (((i + count) < length) && (mode[i + count] == start_mode));
- return count;
- }
- /* Calculate the actual bitlength of the proposed binary string */
- static int qr_calc_binlen(const int version, char mode[], const unsigned int ddata[], const int length,
- const int mode_preset, const int gs1, const int eci, const int debug_print) {
- int i, j;
- char currentMode;
- int count = 0;
- int alphalength;
- int blocklength;
- if (!mode_preset) {
- qr_define_mode(mode, ddata, length, gs1, version, debug_print);
- }
- currentMode = ' '; /* Null */
- if (eci != 0) { /* Not applicable to MICROQR */
- count += 4;
- if (eci <= 127) {
- count += 8;
- } else if (eci <= 16383) {
- count += 16;
- } else {
- count += 24;
- }
- }
- for (i = 0; i < length; i++) {
- if (mode[i] != currentMode) {
- count += qr_mode_bits(version) + qr_cci_bits(version, mode[i]);
- blocklength = qr_blockLength(i, mode, length);
- switch (mode[i]) {
- case 'K':
- count += (blocklength * 13);
- break;
- case 'B':
- for (j = i; j < (i + blocklength); j++) {
- if (ddata[j] > 0xff) {
- count += 16;
- } else {
- count += 8;
- }
- }
- break;
- case 'A':
- alphalength = blocklength;
- if (gs1) {
- /* In alphanumeric mode % becomes %% */
- for (j = i; j < (i + blocklength); j++) {
- if (ddata[j] == '%') {
- alphalength++;
- }
- }
- }
- switch (alphalength % 2) {
- case 0:
- count += (alphalength / 2) * 11;
- break;
- case 1:
- count += ((alphalength - 1) / 2) * 11;
- count += 6;
- break;
- }
- break;
- case 'N':
- switch (blocklength % 3) {
- case 0:
- count += (blocklength / 3) * 10;
- break;
- case 1:
- count += ((blocklength - 1) / 3) * 10;
- count += 4;
- break;
- case 2:
- count += ((blocklength - 2) / 3) * 10;
- count += 7;
- break;
- }
- break;
- }
- currentMode = mode[i];
- }
- }
- return count;
- }
- /* Call `qr_calc_binlen()` on each segment */
- static int qr_calc_binlen_segs(const int version, char mode[], const unsigned int ddata[],
- const struct zint_seg segs[], const int seg_count, const struct zint_structapp *p_structapp,
- const int mode_preset, const int gs1, const int debug_print) {
- int i;
- int count = 0;
- const unsigned int *dd = ddata;
- char *m = mode;
- if (p_structapp) {
- count += 4 + 8 + 8;
- }
- if (gs1) { /* Not applicable to MICROQR */
- if (version < RMQR_VERSION) {
- count += 4;
- } else {
- count += 3;
- }
- }
- for (i = 0; i < seg_count; i++) {
- count += qr_calc_binlen(version, m, dd, segs[i].length, mode_preset, gs1, segs[i].eci, debug_print);
- m += segs[i].length;
- dd += segs[i].length;
- }
- if (debug_print) {
- printf("Estimated Binary Length: %d (version %d, gs1 %d)\n", count, version, gs1);
- }
- return count;
- }
- /* Helper to process source data into `ddata` array */
- static int qr_prep_data(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count,
- unsigned int ddata[]) {
- int warn_number = 0;
- int i;
- /* If ZINT_FULL_MULTIBYTE use Kanji mode in DATA_MODE or for non-Shift JIS in UNICODE_MODE */
- const int full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE;
- if ((symbol->input_mode & 0x07) == DATA_MODE) {
- sjis_cpy_segs(segs, seg_count, ddata, full_multibyte);
- } else {
- unsigned int *dd = ddata;
- for (i = 0; i < seg_count; i++) {
- int done = 0;
- if (segs[i].eci != 20 || seg_count > 1) { /* Unless ECI 20 (Shift JIS) or have multiple segments */
- /* Try other encodings (ECI 0 defaults to ISO/IEC 8859-1) */
- int error_number = sjis_utf8_to_eci(segs[i].eci, segs[i].source, &segs[i].length, dd, full_multibyte);
- if (error_number == 0) {
- done = 1;
- } else if (segs[i].eci || seg_count > 1) {
- return errtxtf(error_number, symbol, 575, "Invalid character in input for ECI '%d'", segs[i].eci);
- }
- }
- if (!done) {
- /* Try Shift-JIS */
- int error_number = sjis_utf8(symbol, segs[i].source, &segs[i].length, dd);
- if (error_number != 0) {
- return error_number;
- }
- if (segs[i].eci != 20) {
- warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 760,
- "Converted to Shift JIS but no ECI specified");
- }
- }
- dd += segs[i].length;
- }
- }
- return warn_number;
- }
- INTERNAL int qrcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
- int warn_number;
- int i, j, est_binlen, prev_est_binlen;
- int ecc_level, autosize, version, max_cw, target_codewords, blocks, size;
- int bitmask;
- int user_mask;
- int canShrink;
- int size_squared;
- const struct zint_structapp *p_structapp = NULL;
- const int gs1 = ((symbol->input_mode & 0x07) == GS1_MODE);
- const int fast_encode = symbol->input_mode & FAST_MODE;
- const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
- const int eci_length_segs = get_eci_length_segs(segs, seg_count);
- struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count);
- unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * eci_length_segs);
- char *mode = (char *) z_alloca(eci_length_segs);
- char *prev_mode = (char *) z_alloca(eci_length_segs);
- unsigned char *datastream;
- unsigned char *fullstream;
- unsigned char *grid;
- user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 8 */
- if (user_mask > 8) {
- user_mask = 0; /* Ignore */
- }
- segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECIs & protect lengths) */
- warn_number = qr_prep_data(symbol, local_segs, seg_count, ddata);
- if (warn_number >= ZINT_ERROR) {
- return warn_number;
- }
- if (symbol->structapp.count) {
- if (symbol->structapp.count < 2 || symbol->structapp.count > 16) {
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 750,
- "Structured Append count '%d' out of range (2 to 16)", symbol->structapp.count);
- }
- if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) {
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 751,
- "Structured Append index '%1$d' out of range (1 to count %2$d)",
- symbol->structapp.index, symbol->structapp.count);
- }
- if (symbol->structapp.id[0]) {
- int id, id_len;
- for (id_len = 1; id_len < 4 && symbol->structapp.id[id_len]; id_len++);
- if (id_len > 3) { /* Max value 255 */
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 752,
- "Structured Append ID length %d too long (3 digit maximum)", id_len);
- }
- id = to_int((const unsigned char *) symbol->structapp.id, id_len);
- if (id == -1) {
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 753, "Invalid Structured Append ID (digits only)");
- }
- if (id > 255) {
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 754,
- "Structured Append ID value '%d' out of range (0 to 255)", id);
- }
- }
- p_structapp = &symbol->structapp;
- }
- /* GS1 General Specifications 22.0 section 5.7.3 says Structured Append and ECIs not supported
- for GS1 QR Code so check and return ZINT_WARN_NONCOMPLIANT if either true */
- if (gs1 && warn_number == 0) {
- for (i = 0; i < seg_count; i++) {
- if (local_segs[i].eci) {
- warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 755,
- "Using ECI in GS1 mode not supported by GS1 standards");
- break;
- }
- }
- if (warn_number == 0 && p_structapp) {
- warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 756,
- "Using Structured Append in GS1 mode not supported by GS1 standards");
- }
- }
- est_binlen = qr_calc_binlen_segs(40, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/, gs1,
- debug_print);
- if ((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) {
- ecc_level = symbol->option_1 - 1;
- } else {
- ecc_level = QR_LEVEL_L;
- }
- max_cw = qr_data_codewords[ecc_level][39];
- if (est_binlen > (8 * max_cw)) {
- if (ecc_level == QR_LEVEL_L) {
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 567, "Input too long, requires %1$d codewords (maximum %2$d)",
- (est_binlen + 7) / 8, max_cw);
- }
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 561,
- "Input too long for ECC level %1$c, requires %2$d codewords (maximum %3$d)",
- qr_ecc_level_names[ecc_level], (est_binlen + 7) / 8, max_cw);
- }
- autosize = 40;
- for (i = 39; i >= 0; i--) {
- if ((8 * qr_data_codewords[ecc_level][i]) >= est_binlen) {
- autosize = i + 1;
- }
- }
- if (autosize != 40) {
- /* Save version 40 estimate in case incorrect costings in `qr_define_mode()` lead to its `mode` being better
- than current lower version one */
- prev_est_binlen = est_binlen;
- est_binlen = qr_calc_binlen_segs(autosize, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/,
- gs1, debug_print);
- if (prev_est_binlen < est_binlen) { /* Shouldn't happen */
- assert(0); /* Not reached (hopefully) */
- /* Defensively use version 40 `mode` to avoid crashes (ticket #300) */
- est_binlen = qr_calc_binlen_segs(40, mode, ddata, local_segs, seg_count, p_structapp, 0 /*mode_preset*/,
- gs1, debug_print);
- assert(est_binlen == prev_est_binlen);
- }
- }
- /* Now see if the optimised binary will fit in a smaller symbol. */
- canShrink = 1;
- do {
- if (autosize == 1) {
- canShrink = 0;
- } else {
- prev_est_binlen = est_binlen;
- memcpy(prev_mode, mode, eci_length_segs);
- est_binlen = qr_calc_binlen_segs(autosize - 1, mode, ddata, local_segs, seg_count, p_structapp,
- 0 /*mode_preset*/, gs1, debug_print);
- if ((8 * qr_data_codewords[ecc_level][autosize - 2]) < est_binlen) {
- canShrink = 0;
- }
- if (canShrink == 1) {
- /* Optimisation worked - data will fit in a smaller symbol */
- autosize--;
- } else {
- /* Data did not fit in the smaller symbol, revert to original size */
- est_binlen = prev_est_binlen;
- memcpy(mode, prev_mode, eci_length_segs);
- }
- }
- } while (canShrink == 1);
- version = autosize;
- if ((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) {
- /* If the user has selected a larger symbol than the smallest available,
- then use the size the user has selected, and re-optimise for this
- symbol size.
- */
- if (symbol->option_2 > version) {
- version = symbol->option_2;
- est_binlen = qr_calc_binlen_segs(symbol->option_2, mode, ddata, local_segs, seg_count, p_structapp,
- 0 /*mode_preset*/, gs1, debug_print);
- }
- if (symbol->option_2 < version) {
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 569,
- "Input too long for Version %1$d-%2$c, requires %3$d codewords (maximum %4$d)",
- symbol->option_2, qr_ecc_level_names[ecc_level], (est_binlen + 7) / 8,
- qr_data_codewords[ecc_level][symbol->option_2 - 1]);
- }
- }
- /* Ensure maxium error correction capacity unless user-specified */
- if (symbol->option_1 == -1 || symbol->option_1 - 1 != ecc_level) {
- if (est_binlen <= qr_data_codewords[QR_LEVEL_H][version - 1] * 8) {
- ecc_level = QR_LEVEL_H;
- } else if (est_binlen <= qr_data_codewords[QR_LEVEL_Q][version - 1] * 8) {
- ecc_level = QR_LEVEL_Q;
- } else if (est_binlen <= qr_data_codewords[QR_LEVEL_M][version - 1] * 8) {
- ecc_level = QR_LEVEL_M;
- }
- }
- target_codewords = qr_data_codewords[ecc_level][version - 1];
- blocks = qr_blocks[ecc_level][version - 1];
- if (debug_print) {
- printf("Minimum codewords: %d\n", (est_binlen + 7) / 8);
- printf("Selected version: %d-%c (%dx%d)\n",
- version, qr_ecc_level_names[ecc_level], qr_sizes[version - 1], qr_sizes[version - 1]);
- printf("Number of data codewords in symbol: %d\n", target_codewords);
- printf("Number of ECC blocks: %d\n", blocks);
- }
- datastream = (unsigned char *) z_alloca(target_codewords + 1);
- fullstream = (unsigned char *) z_alloca(qr_total_codewords[version - 1] + 1);
- (void) qr_binary_segs(datastream, version, target_codewords, mode, ddata, local_segs, seg_count, p_structapp, gs1,
- est_binlen, debug_print);
- #ifdef ZINT_TEST
- if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords);
- #endif
- qr_add_ecc(fullstream, datastream, version, target_codewords, blocks, debug_print);
- size = qr_sizes[version - 1];
- size_squared = size * size;
- grid = (unsigned char *) z_alloca(size_squared);
- memset(grid, 0, size_squared);
- qr_setup_grid(grid, size, version);
- qr_populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]);
- if (version >= 7) {
- qr_add_version_info(grid, size, version);
- }
- bitmask = qr_apply_bitmask(grid, size, ecc_level, user_mask, fast_encode, debug_print);
- qr_add_format_info(grid, size, ecc_level, bitmask);
- symbol->width = size;
- symbol->rows = size;
- for (i = 0; i < size; i++) {
- int r = i * size;
- for (j = 0; j < size; j++) {
- if (grid[r + j] & 0x01) {
- set_module(symbol, i, j);
- }
- }
- symbol->row_height[i] = 1;
- }
- symbol->height = size;
- return warn_number;
- }
- /* Write terminator, padding & ECC */
- static int microqr_end(struct zint_symbol *symbol, char binary_data[], int bp, const int ecc_level,
- const int version) {
- int i, j;
- int bits_left;
- unsigned char data_blocks[17];
- unsigned char ecc_blocks[15];
- rs_t rs;
- const int terminator_bits = qr_terminator_bits(MICROQR_VERSION + version);
- const int bits_total = microqr_data[ecc_level][version][0];
- const int data_codewords = microqr_data[ecc_level][version][1];
- const int ecc_codewords = microqr_data[ecc_level][version][2];
- const int bits_end = version == 0 || version == 2 ? 4 : 8;
- /* Add terminator */
- bits_left = bits_total - bp;
- if (bits_left <= terminator_bits) {
- if (bits_left) {
- bp = bin_append_posn(0, bits_left, binary_data, bp);
- bits_left = 0;
- }
- } else {
- bp = bin_append_posn(0, terminator_bits, binary_data, bp);
- bits_left -= terminator_bits;
- }
- if (symbol->debug & ZINT_DEBUG_PRINT) {
- printf("M%d Terminated binary (%d): %.*s (bits_left %d)\n", version + 1, bp, bp, binary_data, bits_left);
- }
- /* Manage last (4-bit) block */
- if (bits_end == 4 && bits_left && bits_left <= 4) {
- bp = bin_append_posn(0, bits_left, binary_data, bp);
- bits_left = 0;
- }
- if (bits_left) {
- /* Complete current byte */
- int remainder = 8 - (bp % 8);
- if (remainder != 8) {
- bp = bin_append_posn(0, remainder, binary_data, bp);
- bits_left -= remainder;
- }
- /* Add padding */
- if (bits_end == 4 && bits_left > 4) {
- bits_left -= 4;
- }
- remainder = bits_left / 8;
- for (i = 0; i < remainder; i++) {
- bp = bin_append_posn(i & 1 ? 0x11 : 0xEC, 8, binary_data, bp);
- }
- if (bits_end == 4) {
- bp = bin_append_posn(0, 4, binary_data, bp);
- }
- }
- assert((bp & 0x07) == 8 - bits_end);
- /* Copy data into codewords */
- for (i = 0; i < data_codewords; i++) {
- const int bits = i + 1 == data_codewords ? bits_end : 8;
- data_blocks[i] = 0;
- for (j = 0; j < bits; j++) {
- if (binary_data[(i * 8) + j] == '1') {
- data_blocks[i] |= 0x80 >> j;
- }
- }
- }
- #ifdef ZINT_TEST
- if (symbol->debug & ZINT_DEBUG_TEST) {
- char bp_buf[10];
- debug_test_codeword_dump(symbol, data_blocks, data_codewords);
- sprintf(bp_buf, "%d", bp); /* Append `bp` to detect padding errors */
- errtxt_adj(0, symbol, "%s (%s)", bp_buf);
- }
- #endif
- /* Calculate Reed-Solomon error codewords */
- rs_init_gf(&rs, 0x11d);
- rs_init_code(&rs, ecc_codewords, 0);
- rs_encode(&rs, data_codewords, data_blocks, ecc_blocks);
- /* Add Reed-Solomon codewords to binary data */
- for (i = 0; i < ecc_codewords; i++) {
- bp = bin_append_posn(ecc_blocks[i], 8, binary_data, bp);
- }
- return bp;
- }
- static void microqr_setup_grid(unsigned char *grid, const int size) {
- int i, toggle = 1;
- /* Add timing patterns */
- for (i = 0; i < size; i++) {
- if (toggle == 1) {
- grid[i] = 0x21;
- grid[(i * size)] = 0x21;
- toggle = 0;
- } else {
- grid[i] = 0x20;
- grid[(i * size)] = 0x20;
- toggle = 1;
- }
- }
- /* Add finder patterns */
- qr_place_finder(grid, size, 0, 0);
- /* Add separators */
- for (i = 0; i < 7; i++) {
- grid[(7 * size) + i] = 0x10;
- grid[(i * size) + 7] = 0x10;
- }
- grid[(7 * size) + 7] = 0x10;
- /* Reserve space for format information */
- for (i = 0; i < 8; i++) {
- grid[(8 * size) + i] |= 0x20;
- grid[(i * size) + 8] |= 0x20;
- }
- grid[(8 * size) + 8] |= 20;
- }
- static void microqr_populate_grid(unsigned char *grid, const int size, const char full_stream[], int bp) {
- int direction = 1; /* up */
- int row = 0; /* right hand side */
- int i;
- int y;
- y = size - 1;
- i = 0;
- do {
- int x = (size - 2) - (row * 2);
- if (!(grid[(y * size) + (x + 1)] & 0xf0)) {
- if (full_stream[i] == '1') {
- grid[(y * size) + (x + 1)] = 0x01;
- } else {
- grid[(y * size) + (x + 1)] = 0x00;
- }
- i++;
- }
- if (i < bp) {
- if (!(grid[(y * size) + x] & 0xf0)) {
- if (full_stream[i] == '1') {
- grid[(y * size) + x] = 0x01;
- } else {
- grid[(y * size) + x] = 0x00;
- }
- i++;
- }
- }
- if (direction) {
- y--;
- } else {
- y++;
- }
- if (y == 0) {
- /* reached the top */
- row++;
- y = 1;
- direction = 0;
- }
- if (y == size) {
- /* reached the bottom */
- row++;
- y = size - 1;
- direction = 1;
- }
- } while (i < bp);
- }
- static int microqr_evaluate(const unsigned char *grid, const int size, const int pattern) {
- int sum1, sum2, i, filter = 0, retval;
- switch (pattern) {
- case 0: filter = 0x01;
- break;
- case 1: filter = 0x02;
- break;
- case 2: filter = 0x04;
- break;
- case 3: filter = 0x08;
- break;
- }
- sum1 = 0;
- sum2 = 0;
- for (i = 1; i < size; i++) {
- if (grid[(i * size) + size - 1] & filter) {
- sum1++;
- }
- if (grid[((size - 1) * size) + i] & filter) {
- sum2++;
- }
- }
- if (sum1 <= sum2) {
- retval = (sum1 * 16) + sum2;
- } else {
- retval = (sum2 * 16) + sum1;
- }
- return retval;
- }
- static int microqr_apply_bitmask(unsigned char *grid, const int size, const int user_mask, const int debug_print) {
- int x, y;
- int r, k;
- int bit;
- int pattern, value[4];
- int best_pattern;
- int size_squared = size * size;
- unsigned char *mask = (unsigned char *) z_alloca(size_squared);
- unsigned char *eval = (unsigned char *) z_alloca(size_squared);
- /* Perform data masking */
- memset(mask, 0, size_squared);
- for (y = 0; y < size; y++) {
- r = y * size;
- for (x = 0; x < size; x++) {
- if (!(grid[r + x] & 0xf0)) {
- if ((y & 1) == 0) {
- mask[r + x] |= 0x01;
- }
- if ((((y / 2) + (x / 3)) & 1) == 0) {
- mask[r + x] |= 0x02;
- }
- if (((((y * x) & 1) + ((y * x) % 3)) & 1) == 0) {
- mask[r + x] |= 0x04;
- }
- if (((((y + x) & 1) + ((y * x) % 3)) & 1) == 0) {
- mask[r + x] |= 0x08;
- }
- }
- }
- }
- if (user_mask) {
- best_pattern = user_mask - 1;
- } else {
- for (k = 0; k < size_squared; k++) {
- if (grid[k] & 0x01) {
- eval[k] = mask[k] ^ 0xff;
- } else {
- eval[k] = mask[k];
- }
- }
- /* Evaluate result */
- best_pattern = 0;
- for (pattern = 0; pattern < 4; pattern++) {
- value[pattern] = microqr_evaluate(eval, size, pattern);
- if (value[pattern] > value[best_pattern]) {
- best_pattern = pattern;
- }
- }
- }
- if (debug_print) {
- printf("Mask: %d (%s)", best_pattern, user_mask ? "specified" : "automatic");
- if (!user_mask) {
- for (pattern = 0; pattern < 4; pattern++) printf(" %d:%d", pattern, value[pattern]);
- }
- fputc('\n', stdout);
- }
- /* Apply mask */
- bit = 1 << best_pattern;
- for (k = 0; k < size_squared; k++) {
- if (mask[k] & bit) {
- grid[k] ^= 0x01;
- }
- }
- return best_pattern;
- }
- INTERNAL int microqr(struct zint_symbol *symbol, unsigned char source[], int length) {
- int i, size, j;
- char full_stream[200];
- int bp;
- int full_multibyte;
- int user_mask;
- unsigned int ddata[40];
- char mode[40];
- int alpha_used = 0, byte_or_kanji_used = 0;
- int version_valid[4];
- int binary_count[4];
- int ecc_level, version;
- int bitmask, format, format_full;
- int size_squared;
- struct zint_seg segs[1];
- const int seg_count = 1;
- const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
- unsigned char *grid;
- if (length > 35) {
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 562, "Input length %d too long (maximum 35)", length);
- }
- /* Check option 1 in combination with option 2 */
- ecc_level = QR_LEVEL_L;
- if (symbol->option_1 >= 1 && symbol->option_1 <= 4) {
- if (symbol->option_1 == 4) {
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 566, "Error correction level H not available");
- }
- if (symbol->option_2 >= 1 && symbol->option_2 <= 4) {
- if (symbol->option_2 == 1 && symbol->option_1 != 1) {
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 574,
- "Version M1 supports error correction level L only");
- }
- if (symbol->option_2 != 4 && symbol->option_1 == 3) {
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 563, "Error correction level Q requires Version M4");
- }
- }
- ecc_level = symbol->option_1 - 1;
- }
- /* If ZINT_FULL_MULTIBYTE use Kanji mode in DATA_MODE or for non-Shift JIS in UNICODE_MODE */
- full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE;
- user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 4 */
- if (user_mask > 4) {
- user_mask = 0; /* Ignore */
- }
- if ((symbol->input_mode & 0x07) == DATA_MODE) {
- sjis_cpy(source, &length, ddata, full_multibyte);
- } else {
- /* Try ISO 8859-1 conversion first */
- int error_number = sjis_utf8_to_eci(3, source, &length, ddata, full_multibyte);
- if (error_number != 0) {
- /* Try Shift-JIS */
- error_number = sjis_utf8(symbol, source, &length, ddata);
- if (error_number != 0) {
- return error_number;
- }
- }
- }
- /* Determine if alpha (excluding numerics), byte or kanji used */
- for (i = 0; i < length && (alpha_used == 0 || byte_or_kanji_used == 0); i++) {
- if (!z_isdigit(ddata[i])) {
- if (qr_is_alpha(ddata[i], 0 /*gs1*/)) {
- alpha_used = 1;
- } else {
- byte_or_kanji_used = 1;
- }
- }
- }
- for (i = 0; i < 4; i++) {
- version_valid[i] = 1;
- }
- /* Eliminate possible versions depending on type of content */
- if (byte_or_kanji_used) {
- version_valid[0] = 0;
- version_valid[1] = 0;
- } else if (alpha_used) {
- version_valid[0] = 0;
- }
- /* Eliminate possible versions depending on error correction level specified */
- if (ecc_level == QR_LEVEL_Q) {
- version_valid[0] = 0;
- version_valid[1] = 0;
- version_valid[2] = 0;
- } else if (ecc_level == QR_LEVEL_M) {
- version_valid[0] = 0;
- }
- segs[0].source = source;
- segs[0].length = length;
- segs[0].eci = 0;
- /* Determine length of binary data */
- for (i = 0; i < 4; i++) {
- if (version_valid[i]) {
- binary_count[i] = qr_calc_binlen_segs(MICROQR_VERSION + i, mode, ddata, segs, seg_count,
- NULL /*p_structapp*/, 0 /*mode_preset*/, 0 /*gs1*/, debug_print);
- } else {
- binary_count[i] = 128 + 1;
- }
- }
- /* Eliminate possible versions depending on binary length and error correction level specified */
- if (binary_count[3] > microqr_data[ecc_level][3][0]) {
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 565,
- "Input too long for Version M4-%1$c, requires %2$d codewords (maximum %3$d)",
- qr_ecc_level_names[ecc_level], (binary_count[3] + 7) / 8, microqr_data[ecc_level][3][1]);
- }
- for (i = 0; i < 3; i++) {
- if (binary_count[i] > microqr_data[ecc_level][i][0]) {
- version_valid[i] = 0;
- }
- }
- /* Auto-select lowest valid size */
- version = 3;
- if (version_valid[2]) {
- version = 2;
- }
- if (version_valid[1]) {
- version = 1;
- }
- if (version_valid[0]) {
- version = 0;
- }
- /* Get version from user */
- if ((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) {
- if (symbol->option_2 == 1 && (i = not_sane(NEON_F, source, length))) {
- return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 758,
- "Invalid character at position %d in input for Version M1 (digits only)", i);
- } else if (symbol->option_2 == 2 && not_sane(QR_ALPHA, source, length)) {
- return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 759,
- "Invalid character in input for Version M2 (digits, A-Z, space and \"$%*+-./:\" only)");
- }
- if (symbol->option_2 - 1 >= version) {
- version = symbol->option_2 - 1;
- } else {
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 570,
- "Input too long for Version M%1$d-%2$c, requires %3$d codewords (maximum %4$d)",
- symbol->option_2, qr_ecc_level_names[ecc_level], (binary_count[version] + 7) / 8,
- microqr_data[ecc_level][symbol->option_2 - 1][1]);
- }
- }
- /* If there is enough unused space then increase the error correction level, unless user-specified */
- if (version && (symbol->option_1 == -1 || symbol->option_1 - 1 != ecc_level)) {
- if (binary_count[version] <= microqr_data[QR_LEVEL_Q][version][0]) {
- ecc_level = QR_LEVEL_Q;
- } else if (binary_count[version] <= microqr_data[QR_LEVEL_M][version][0]) {
- ecc_level = QR_LEVEL_M;
- }
- }
- qr_define_mode(mode, ddata, length, 0 /*gs1*/, MICROQR_VERSION + version, debug_print);
- bp = qr_binary_segs((unsigned char *) full_stream, MICROQR_VERSION + version, 0 /*target_codewords*/, mode, ddata,
- segs, seg_count, NULL /*p_structapp*/, 0 /*gs1*/, binary_count[version], debug_print);
- if (debug_print) printf("Binary (%d): %.*s\n", bp, bp, full_stream);
- bp = microqr_end(symbol, full_stream, bp, ecc_level, version);
- size = microqr_sizes[version];
- size_squared = size * size;
- grid = (unsigned char *) z_alloca(size_squared);
- memset(grid, 0, size_squared);
- microqr_setup_grid(grid, size);
- microqr_populate_grid(grid, size, full_stream, bp);
- bitmask = microqr_apply_bitmask(grid, size, user_mask, debug_print);
- /* Add format data */
- format = version ? (version - 1) * 2 + ecc_level + 1 : 0;
- if (debug_print) {
- printf("Version: M%d-%c, Size: %dx%d, Format: %d\n",
- version + 1, qr_ecc_level_names[ecc_level], size, size, format);
- }
- format_full = qr_annex_c1[(format << 2) + bitmask];
- for (i = 1; i <= 8; i++) {
- grid[(8 * size) + i] |= (format_full >> (15 - i)) & 0x01;
- }
- for (i = 7; i >= 1; i--) {
- grid[(i * size) + 8] |= (format_full >> (i - 1)) & 0x01;
- }
- symbol->width = size;
- symbol->rows = size;
- for (i = 0; i < size; i++) {
- for (j = 0; j < size; j++) {
- if (grid[(i * size) + j] & 0x01) {
- set_module(symbol, i, j);
- }
- }
- symbol->row_height[i] = 1;
- }
- symbol->height = size;
- return 0;
- }
- /* For UPNQR the symbol size and error correction capacity is fixed */
- INTERNAL int upnqr(struct zint_symbol *symbol, unsigned char source[], int length) {
- int i, j, r, est_binlen;
- int ecc_level, version, target_codewords, blocks, size;
- int bitmask, error_number;
- int user_mask;
- int size_squared;
- struct zint_seg segs[1];
- const int seg_count = 1;
- const int fast_encode = symbol->input_mode & FAST_MODE;
- const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
- unsigned char *datastream;
- unsigned char *fullstream;
- unsigned char *grid;
- unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * length);
- char *mode = (char *) z_alloca(length + 1);
- unsigned char *preprocessed = (unsigned char *) z_alloca(length + 1);
- symbol->eci = 4; /* Set before any processing */
- user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 8 */
- if (user_mask > 8) {
- user_mask = 0; /* Ignore */
- }
- switch (symbol->input_mode & 0x07) {
- case DATA_MODE:
- /* Input is already in ISO-8859-2 format */
- for (i = 0; i < length; i++) {
- ddata[i] = source[i];
- mode[i] = 'B';
- }
- break;
- case GS1_MODE: /* Should never happen as checked before being called */
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 571,
- "UPNQR does not support GS1 data"); /* Not reached */
- break;
- case UNICODE_MODE:
- error_number = utf8_to_eci(4, source, preprocessed, &length);
- if (error_number != 0) {
- return errtxt(error_number, symbol, 572, "Invalid character in input for ECI '4'");
- }
- for (i = 0; i < length; i++) {
- ddata[i] = preprocessed[i];
- mode[i] = 'B';
- }
- break;
- }
- segs[0].source = source;
- segs[0].length = length;
- segs[0].eci = 4;
- est_binlen = qr_calc_binlen_segs(15, mode, ddata, segs, seg_count, NULL /*p_structapp*/, 1 /*mode_preset*/,
- 0 /*gs1*/, debug_print);
- ecc_level = QR_LEVEL_M;
- if (est_binlen > 3320) {
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 573, "Input too long, requires %d codewords (maximum 415)",
- (est_binlen + 7) / 8);
- }
- version = 15; /* 77 x 77 */
- target_codewords = qr_data_codewords[ecc_level][version - 1];
- blocks = qr_blocks[ecc_level][version - 1];
- datastream = (unsigned char *) z_alloca(target_codewords + 1);
- fullstream = (unsigned char *) z_alloca(qr_total_codewords[version - 1] + 1);
- (void) qr_binary_segs(datastream, version, target_codewords, mode, ddata, segs, seg_count, NULL /*p_structapp*/,
- 0 /*gs1*/, est_binlen, debug_print);
- #ifdef ZINT_TEST
- if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords);
- #endif
- qr_add_ecc(fullstream, datastream, version, target_codewords, blocks, debug_print);
- size = qr_sizes[version - 1];
- size_squared = size * size;
- grid = (unsigned char *) z_alloca(size_squared);
- memset(grid, 0, size_squared);
- qr_setup_grid(grid, size, version);
- qr_populate_grid(grid, size, size, fullstream, qr_total_codewords[version - 1]);
- qr_add_version_info(grid, size, version);
- bitmask = qr_apply_bitmask(grid, size, ecc_level, user_mask, fast_encode, debug_print);
- qr_add_format_info(grid, size, ecc_level, bitmask);
- symbol->width = size;
- symbol->rows = size;
- for (i = 0; i < size; i++) {
- r = i * size;
- for (j = 0; j < size; j++) {
- if (grid[r + j] & 0x01) {
- set_module(symbol, i, j);
- }
- }
- symbol->row_height[i] = 1;
- }
- symbol->height = size;
- return 0;
- }
- static const char rmqr_version_names[38][8] = {
- "R7x43", "R7x59", "R7x77", "R7x99", "R7x139", "R9x43", "R9x59", "R9x77",
- "R9x99", "R9x139", "R11x27", "R11x43", "R11x59", "R11x77", "R11x99", "R11x139",
- "R13x27", "R13x43", "R13x59", "R13x77", "R13x99", "R13x139", "R15x43", "R15x59",
- "R15x77", "R15x99", "R15x139", "R17x43", "R17x59", "R17x77", "R17x99", "R17x139",
- "R7xW", "R9xW", "R11xW", "R13xW", "R15xW", "R17xW",
- };
- static void rmqr_setup_grid(unsigned char *grid, const int h_size, const int v_size) {
- int i, j;
- char alignment[] = {0x1F, 0x11, 0x15, 0x11, 0x1F};
- int h_version, finder_position;
- /* Add timing patterns - top and bottom */
- for (i = 0; i < h_size; i++) {
- if (i % 2) {
- grid[i] = 0x20;
- grid[((v_size - 1) * h_size) + i] = 0x20;
- } else {
- grid[i] = 0x21;
- grid[((v_size - 1) * h_size) + i] = 0x21;
- }
- }
- /* Add timing patterns - left and right */
- for (i = 0; i < v_size; i++) {
- if (i % 2) {
- grid[i * h_size] = 0x20;
- grid[(i * h_size) + (h_size - 1)] = 0x20;
- } else {
- grid[i * h_size] = 0x21;
- grid[(i * h_size) + (h_size - 1)] = 0x21;
- }
- }
- /* Add finder pattern */
- qr_place_finder(grid, h_size, 0, 0); /* This works because finder is always top left */
- /* Add finder sub-pattern to bottom right */
- for (i = 0; i < 5; i++) {
- for (j = 0; j < 5; j++) {
- if (alignment[j] & 0x10 >> i) {
- grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x11;
- } else {
- grid[((v_size - 5) * h_size) + (h_size * i) + (h_size - 5) + j] = 0x10;
- }
- }
- }
- /* Add corner finder pattern - bottom left */
- grid[(v_size - 2) * h_size] = 0x11;
- grid[((v_size - 2) * h_size) + 1] = 0x10;
- grid[((v_size - 1) * h_size) + 1] = 0x11;
- /* Add corner finder pattern - top right */
- grid[h_size - 2] = 0x11;
- grid[(h_size * 2) - 2] = 0x10;
- grid[(h_size * 2) - 1] = 0x11;
- /* Add seperator */
- for (i = 0; i < 7; i++) {
- grid[(i * h_size) + 7] = 0x20;
- }
- if (v_size > 7) {
- /* Note for v_size = 9 this overrides the bottom right corner finder pattern */
- for (i = 0; i < 8; i++) {
- grid[(7 * h_size) + i] = 0x20;
- }
- }
- /* Add alignment patterns */
- if (h_size > 27) {
- h_version = 0; /* Suppress compiler warning [-Wmaybe-uninitialized] */
- for (i = 0; i < 5; i++) {
- if (h_size == rmqr_width[i]) {
- h_version = i;
- break;
- }
- }
- for (i = 0; i < 4; i++) {
- finder_position = rmqr_table_d1[(h_version * 4) + i];
- if (finder_position != 0) {
- for (j = 0; j < v_size; j++) {
- if (j % 2) {
- grid[(j * h_size) + finder_position] = 0x10;
- } else {
- grid[(j * h_size) + finder_position] = 0x11;
- }
- }
- /* Top square */
- grid[h_size + finder_position - 1] = 0x11;
- grid[(h_size * 2) + finder_position - 1] = 0x11;
- grid[h_size + finder_position + 1] = 0x11;
- grid[(h_size * 2) + finder_position + 1] = 0x11;
- /* Bottom square */
- grid[(h_size * (v_size - 3)) + finder_position - 1] = 0x11;
- grid[(h_size * (v_size - 2)) + finder_position - 1] = 0x11;
- grid[(h_size * (v_size - 3)) + finder_position + 1] = 0x11;
- grid[(h_size * (v_size - 2)) + finder_position + 1] = 0x11;
- }
- }
- }
- /* Reserve space for format information */
- for (i = 0; i < 5; i++) {
- for (j = 0; j < 3; j++) {
- grid[(h_size * (i + 1)) + j + 8] = 0x20;
- grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)] = 0x20;
- }
- }
- grid[(h_size * 1) + 11] = 0x20;
- grid[(h_size * 2) + 11] = 0x20;
- grid[(h_size * 3) + 11] = 0x20;
- grid[(h_size * (v_size - 6)) + (h_size - 5)] = 0x20;
- grid[(h_size * (v_size - 6)) + (h_size - 4)] = 0x20;
- grid[(h_size * (v_size - 6)) + (h_size - 3)] = 0x20;
- }
- /* rMQR according to 2018 draft standard */
- INTERNAL int rmqr(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
- int warn_number;
- int i, j, est_binlen;
- int ecc_level, autosize, version, max_cw, target_codewords, blocks, h_size, v_size;
- int footprint, best_footprint, format_data;
- unsigned int left_format_info, right_format_info;
- const int gs1 = ((symbol->input_mode & 0x07) == GS1_MODE);
- const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
- const int eci_length_segs = get_eci_length_segs(segs, seg_count);
- struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count);
- unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * eci_length_segs);
- char *mode = (char *) z_alloca(eci_length_segs);
- unsigned char *datastream;
- unsigned char *fullstream;
- unsigned char *grid;
- if (symbol->option_1 == 1) {
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 576, "Error correction level L not available in rMQR");
- }
- if (symbol->option_1 == 3) {
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 577, "Error correction level Q not available in rMQR");
- }
- if ((symbol->option_2 < 0) || (symbol->option_2 > 38)) {
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 579, "Version '%d' out of range (1 to 38)",
- symbol->option_2);
- }
- segs_cpy(symbol, segs, seg_count, local_segs);
- warn_number = qr_prep_data(symbol, local_segs, seg_count, ddata);
- if (warn_number >= ZINT_ERROR) {
- return warn_number;
- }
- /* GS1 General Specifications 22.0 section 5.7.3 says ECIs not supported
- for GS1 QR Code so check and return ZINT_WARN_NONCOMPLIANT if true */
- if (gs1 && warn_number == 0) {
- for (i = 0; i < seg_count; i++) {
- if (local_segs[i].eci) {
- warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 757,
- "Using ECI in GS1 mode not supported by GS1 standards");
- break;
- }
- }
- }
- est_binlen = qr_calc_binlen_segs(RMQR_VERSION + 31, mode, ddata, local_segs, seg_count, NULL /*p_structapp*/,
- 0 /*mode_preset*/, gs1, debug_print);
- ecc_level = symbol->option_1 == 4 ? QR_LEVEL_H : QR_LEVEL_M;
- max_cw = rmqr_data_codewords[ecc_level >> 1][31];
- if (est_binlen > (8 * max_cw)) {
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 578,
- "Input too long for ECC level %1$c, requires %2$d codewords (maximum %3$d)",
- qr_ecc_level_names[ecc_level], (est_binlen + 7) / 8, max_cw);
- }
- version = 31; /* Set default to keep compiler happy */
- if (symbol->option_2 == 0) {
- /* Automatic symbol size */
- autosize = 31;
- best_footprint = rmqr_height[31] * rmqr_width[31];
- for (version = 30; version >= 0; version--) {
- est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count,
- NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print);
- footprint = rmqr_height[version] * rmqr_width[version];
- if (8 * rmqr_data_codewords[ecc_level >> 1][version] >= est_binlen) {
- if (footprint < best_footprint) {
- autosize = version;
- best_footprint = footprint;
- }
- }
- }
- version = autosize;
- est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count,
- NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print);
- }
- if ((symbol->option_2 >= 1) && (symbol->option_2 <= 32)) {
- /* User specified symbol size */
- version = symbol->option_2 - 1;
- est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count,
- NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print);
- }
- if (symbol->option_2 >= 33) {
- /* User has specified symbol height only */
- version = rmqr_fixed_height_upper_bound[symbol->option_2 - 32];
- for (i = version - 1; i > rmqr_fixed_height_upper_bound[symbol->option_2 - 33]; i--) {
- est_binlen = qr_calc_binlen_segs(RMQR_VERSION + i, mode, ddata, local_segs, seg_count,
- NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print);
- if (8 * rmqr_data_codewords[ecc_level >> 1][i] >= est_binlen) {
- version = i;
- }
- }
- est_binlen = qr_calc_binlen_segs(RMQR_VERSION + version, mode, ddata, local_segs, seg_count,
- NULL /*p_structapp*/, 0 /*mode_preset*/, gs1, debug_print);
- }
- if (symbol->option_1 == -1) {
- /* Detect if there is enough free space to increase ECC level */
- if (est_binlen < rmqr_data_codewords[QR_LEVEL_H >> 1][version] * 8) {
- ecc_level = QR_LEVEL_H;
- }
- }
- target_codewords = rmqr_data_codewords[ecc_level >> 1][version];
- blocks = rmqr_blocks[ecc_level >> 1][version];
- if (est_binlen > (target_codewords * 8)) {
- /* User has selected a symbol too small for the data */
- assert(symbol->option_2 > 0);
- return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 560,
- "Input too long for Version %1$d %2$s-%3$c, requires %4$d codewords (maximum %5$d)",
- symbol->option_2, rmqr_version_names[symbol->option_2 - 1], qr_ecc_level_names[ecc_level],
- (est_binlen + 7) / 8, target_codewords);
- }
- if (debug_print) {
- printf("Minimum codewords: %d\n", (est_binlen + 7) / 8);
- printf("Selected version: %d = R%dx%d-%c\n",
- (version + 1), rmqr_height[version], rmqr_width[version], qr_ecc_level_names[ecc_level]);
- printf("Number of data codewords in symbol: %d\n", target_codewords);
- printf("Number of ECC blocks: %d\n", blocks);
- }
- datastream = (unsigned char *) z_alloca(target_codewords + 1);
- fullstream = (unsigned char *) z_alloca(rmqr_total_codewords[version] + 1);
- (void) qr_binary_segs(datastream, RMQR_VERSION + version, target_codewords, mode, ddata, local_segs, seg_count,
- NULL /*p_structapp*/, gs1, est_binlen, debug_print);
- #ifdef ZINT_TEST
- if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, target_codewords);
- #endif
- qr_add_ecc(fullstream, datastream, RMQR_VERSION + version, target_codewords, blocks, debug_print);
- h_size = rmqr_width[version];
- v_size = rmqr_height[version];
- grid = (unsigned char *) z_alloca(h_size * v_size);
- memset(grid, 0, h_size * v_size);
- rmqr_setup_grid(grid, h_size, v_size);
- qr_populate_grid(grid, h_size, v_size, fullstream, rmqr_total_codewords[version]);
- /* apply bitmask */
- for (i = 0; i < v_size; i++) {
- int r = i * h_size;
- for (j = 0; j < h_size; j++) {
- if ((grid[r + j] & 0xf0) == 0) {
- /* This is a data module */
- if (((i / 2) + (j / 3)) % 2 == 0) { /* < This is the data mask from section 7.8.2 */
- /* This module needs to be changed */
- grid[r + j] ^= 0x01;
- }
- }
- }
- }
- /* add format information */
- format_data = version;
- if (ecc_level == QR_LEVEL_H) {
- format_data += 32;
- }
- left_format_info = rmqr_format_info_left[format_data];
- right_format_info = rmqr_format_info_right[format_data];
- for (i = 0; i < 5; i++) {
- for (j = 0; j < 3; j++) {
- grid[(h_size * (i + 1)) + j + 8] = (left_format_info >> ((j * 5) + i)) & 0x01;
- grid[(h_size * (v_size - 6)) + (h_size * i) + j + (h_size - 8)]
- = (right_format_info >> ((j * 5) + i)) & 0x01;
- }
- }
- grid[(h_size * 1) + 11] = (left_format_info >> 15) & 0x01;
- grid[(h_size * 2) + 11] = (left_format_info >> 16) & 0x01;
- grid[(h_size * 3) + 11] = (left_format_info >> 17) & 0x01;
- grid[(h_size * (v_size - 6)) + (h_size - 5)] = (right_format_info >> 15) & 0x01;
- grid[(h_size * (v_size - 6)) + (h_size - 4)] = (right_format_info >> 16) & 0x01;
- grid[(h_size * (v_size - 6)) + (h_size - 3)] = (right_format_info >> 17) & 0x01;
- symbol->width = h_size;
- symbol->rows = v_size;
- for (i = 0; i < v_size; i++) {
- int r = i * h_size;
- for (j = 0; j < h_size; j++) {
- if (grid[r + j] & 0x01) {
- set_module(symbol, i, j);
- }
- }
- symbol->row_height[i] = 1;
- }
- symbol->height = v_size;
- return warn_number;
- }
- /* vim: set ts=4 sw=4 et : */
|