diff options
Diffstat (limited to 'Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua')
-rw-r--r-- | Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua | 393 |
1 files changed, 238 insertions, 155 deletions
diff --git a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua index 415719a2f4d..b43bc511d72 100644 --- a/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua +++ b/Master/texmf-dist/scripts/barracuda/lib-barcode/brcd-barcode.lua @@ -1,6 +1,6 @@ --- Barcode abstract class --- Copyright (C) 2019 Roberto Giacomelli +-- Barcode Abstract Class +-- Copyright (C) 2020 Roberto Giacomelli -- Please see LICENSE.TXT for any legal information about present software local Barcode = { @@ -18,11 +18,15 @@ Barcode._available_enc = {-- keys must be lowercase i2of5 = "lib-barcode.brcd-i2of5", -- Interleaved 2 of 5 } Barcode._builder_instances = {} -- encoder builder instances repository +Barcode._encoder_instances = {} -- encoder instances repository -- common parameters to all the barcode objects +Barcode._super_par_order = { + "ax", + "ay", +} Barcode._super_par_def = {} local pardef = Barcode._super_par_def - -- set an Anchor point (ax, ay) relatively to the barcode bounding box -- without considering any text object -- ax = 0, ay = 0 is the lower left corner of the symbol @@ -32,7 +36,6 @@ pardef.ax = { default = 0.0, unit = "sp", -- scaled point isReserved = false, - order = 1, fncheck = function (self, ax, _) --> boolean, err if ax >= 0.0 and ax <= 1.0 then return true, nil end return false, "[OutOfRange] 'ax' out of [0, 1] interval" @@ -43,7 +46,6 @@ pardef.ay = { default = 0.0, unit = "sp", -- scaled point isReserved = false, - order = 2, fncheck = function (self, ay, _) --> boolean, err if ay >= 0.0 and ay <= 1.0 then return true, nil end return false, "[OutOfRange] 'ay' out of [0, 1] interval" @@ -54,120 +56,203 @@ pardef.ay = { -- Barcode methods --- stateless iterator troughtout the ordered parameters collection -local function p_iter(state, i) - i = i + 1 - local t = state[i] - if t then - return i, t +-- extract id from an encoder 'tree name' +local function parse_treename(treename) --> fam, var, name, err + if not type(treename) == "string" then + return nil, nil, nil, "[ArgErr] 'treename' arg must be a string" + end + if treename:find(" ") then + return nil, nil, nil, + "[ArgErr] spaces are not allowed in an encoder identifier" + end + local fam, var, name + -- family name extraction + local idash = treename:find("-") + local icolon = treename:find(":") + if idash then + fam = treename:sub(1, idash - 1) + else + if icolon then + fam = treename:sub(1, icolon - 1) + else + fam = treename + end + end + if fam == "" then + return nil, nil, nil, "[ArgErr] empty encoder id" end + if idash then + if icolon then + var = treename:sub(idash + 1, icolon - 1) + else + var = treename:sub(idash + 1) + end + if var == "" then + return nil, nil, nil, "[ArgErr] empty 'variant' encoder id" + end + end + if icolon then + name = treename:sub(icolon + 1) + if name == "" then + return nil, nil, nil, "[ArgErr] empty 'name' after colon" + end + if name:find("-") then + return nil, nil, nil, "[ArgErr] the name mustn't contain a dash" + end + if name:find(":") then + return nil, nil, nil, "[ArgErr] the name mustn't contain a colon" + end + end + return fam, var, name, nil end -- main iterator on parameter definitions -function Barcode:param_ord_iter() +-- optional argument 'filter' eventually excludes some parameters +-- "*all" -> encoder and Barcode parameters +-- "*enc" -> only encoder parameters +-- "*super" -> only Barcode superclass paramenters +function Barcode:param_ord_iter(filter) + local is_iter_enc, is_iter_super = true, true + if filter then + if type(filter) ~= "string" then + error("[param_ord_iter] 'filter' is not a string") + elseif filter == "*enc" then + is_iter_super = false + elseif filter == "*super" then + is_iter_enc = false + elseif filter ~= "*all" then + error("[param_ord_iter] 'filter' enumeration '"..filter.."' not found") + end + end local state = {} - -- append family parameter - local p2_family = self._par_def -- base family parameters - local fam_len = 0 - if p2_family then - for pname, pdef in pairs(p2_family) do - state[pdef.order] = { - pname = pname, - pdef = pdef, - isSuper = false, - } - fam_len = fam_len + 1 + local ordkey = {} + if is_iter_enc then + local var = self._variant + local p2_family = self._par_def -- base family parameters + local p2_family_var + if var then + local pvar = "_par_def_"..var + p2_family_var = self[pvar] -- variant specific family parameters + end + local p2_idlist = self._par_order + if p2_idlist then -- family parameters + for i, pid in ipairs(p2_idlist) do + if ordkey[pid] then + error("[Ops] duplicated entry in parameter ordered list") + end + ordkey[pid] = true + local pdef -- parameter definition + if var and p2_family_var then + pdef = p2_family_var[pid] + end + pdef = pdef or p2_family[pid] + assert(pdef, "[Ops] parameter definition for option '"..pid.."' not found") + state[i] = { + pname = pid, + pdef = pdef, + isSuper = false, + } + end + end + -- append variant parameters + if var and self._par_def_variant then + local p2_variant = self._par_def_variant[var] + if p2_variant then + local p2_idlist_var = self._par_variant_order[var] -- parameters' list + if p2_idlist_var then + for _, pid in ipairs(p2_idlist_var) do + if ordkey[pid] then + error("[Ops] duplicated entry in variant parameter ordered list") + end + ordkey[pid] = true + local pdef = p2_variant[pid] -- parameter definition + assert(pdef, "[Ops] parameter definition for option '"..pid.."' not found") + state[#state + 1] = { + pname = pid, + pdef = pdef, + isSuper = false, + } + end + end + end end - assert(fam_len == #state) - end - -- append the variant parameters - local var_len = 0 - local var = self._variant - if var then -- specific variant parameters - local p2_variant = assert(self._par_def_variant[var]) - for pname, pdef in pairs(p2_variant) do - if state[pname] then - error("[InternalErr] overriding paramenter '"..pname.."'") + end + if is_iter_super then + -- append the super class parameter to the iterator state + local p1_idlist_super = self._super_par_order + local p1_super = self._super_par_def + for _, pid in ipairs(p1_idlist_super) do + if ordkey[pid] then + error("[Ops] duplicated entry in superclass parameter ordered list") end - state[pdef.order + fam_len] = { - pname = pname, + ordkey[pid] = true + local pdef = p1_super[pid] -- parameter definition + assert(pdef, "[Ops] parameter definition for option '"..pid.."' not found") + state[#state + 1] = { + pname = pid, pdef = pdef, - isSuper = false, + isSuper = true, } - var_len = var_len + 1 end - assert(fam_len + var_len == #state) - end - -- append the super class parameter to the iterator state - local p1 = self._super_par_def - local super_len = 0 - for pname, pdef in pairs(p1) do - if state[pname] then - error("[InternalError] overriding paramenter name '"..pname.."'") + end + -- stateless iterator troughtout the ordered parameters collection + local p_iter = function (st, i) + i = i + 1 + local t = st[i] + if t then + return i, t end - state[fam_len + var_len + pdef.order] = { - pname = pname, - pdef = pdef, - isSuper = true, - } - super_len = super_len + 1 end - assert(super_len + fam_len + var_len == #state) return p_iter, state, 0 end -- encoder costructor -- Symbology can be a family with many variants. This is represented by the --- first argument 'bc_type' formatted as <family>-<variant>. --- in more details: --- <family id><dash char><variant id> if there are variants --- <encoder id> if not --- i.e. when 'bc_type' is the string "ean-13", "ean" is the barcode family and +-- first argument 'tree_name' formatted as <family>-<variant>:<id>. +-- i.e. when 'tree_name' is the string "ean-13", "ean" is the barcode family and -- "13" is its variant name. --- For whose barcodes that do not have variants, 'bc_type' is simply the endoder id --- such as "code128". --- 'id_enc' is an optional identifier useful to retrive an encoder reference later --- 'opt' is an optional table with the user-defined parameters setting up encoders --- -function Barcode:new_encoder(bc_type, id_enc, opt) --> object, err +-- For whose barcodes that do not have variants, 'treename' is simply the +-- encoder id such as in the case of "code128". +-- <id> is an optional identifier useful if there are more than one encoders of +-- the same type +-- 'opt' is an optional table with the user-defined parameters setting up +-- encoders +function Barcode:new_encoder(treename, opt) --> object, err -- argument checking - if type(bc_type) ~= "string" then - return nil, "[ArgErr] 'bc_type' is not a string" - end - local pdash = string.find(bc_type, "-") - local family, variant - if pdash then - family = string.sub(bc_type, 1, pdash - 1) - variant = string.sub(bc_type, pdash + 1) - else - family = bc_type + local family, variant, enc_name, err = parse_treename(treename) + if err then + return err end local av_enc = self._available_enc - if not av_enc[family] then -- is the barcode type a real module? - return nil, "[Err] barcode type '"..family.."' not found" - end - if id_enc == nil then - id_enc = (variant or "") .. "_noname" - elseif type(id_enc) ~= "string" then - return nil, "[ArgErr] provided 'id_enc' is not a string" - end - if type(opt) == "table" or opt == nil then - opt = opt or {} - else - return nil, "[ArgErr] provided 'opt' is wrong" + local mod_path = av_enc[family] + -- check family identifier + if not mod_path then + return nil, "[ArgErr] barcode family '"..family.."' not found" end + -- retrive/load the builder + local builder local tenc = self._builder_instances - local builder; if tenc[family] then -- is the encoder builder already loaded? builder = tenc[family] - else -- loading the encoder builder - local mod_path = av_enc[family] + else -- load the encoder builder builder = require(mod_path) - tenc[family] = assert(builder, "[InternalErr] module not found!") - builder._enc_instances = {} + tenc[family] = builder end - if builder._enc_instances[id_enc] then - return nil, "[Err] 'id_enc' already present" + -- check the variant identifier + local av_var = builder._id_variant + if av_var and variant and (not av_var[variant]) then + local fmt = "[ArgErr] family '%s' does not have '%s' variant" + return nil, string.format(fmt, family, variant) + end + -- check unique encoder identifier + local enc_archive = self._encoder_instances + if enc_archive[treename] then + return nil, "[Err] encoder name '"..treename.."' already exists" + end + if type(opt) == "table" or opt == nil then + opt = opt or {} + else + return nil, "[ArgErr] provided 'opt' is not a table" end local enc = {} -- the new encoder enc.__index = enc @@ -180,19 +265,19 @@ function Barcode:new_encoder(bc_type, id_enc, opt) --> object, err return self[k] end }) - builder._enc_instances[id_enc] = enc - -- param defition + enc_archive[treename] = enc + -- parameters definition for _, tpar in enc:param_ord_iter() do local pname = tpar.pname local pdef = tpar.pdef local isSuper = tpar.isSuper local val = opt[pname] -- param = val if val ~= nil then - local ok, err = pdef:fncheck(val, enc) + local ok, perr = pdef:fncheck(val, enc) if ok then enc[pname] = val - else -- error! - return nil, err + else -- parameter error! + return nil, perr end else -- load the default value of <pname> @@ -206,49 +291,30 @@ function Barcode:new_encoder(bc_type, id_enc, opt) --> object, err end end end - if enc.config then -- this must be called after the parameter definition - enc:config(variant) + if enc._config then -- this must be called after the parameter definition + enc:_config() end return enc, nil end --- retrive encoder object already created --- 'name' is optional in case you didn't assign one to the encoder -function Barcode:enc_by_name(bc_type, name) --> <encoder object>, <err> - if type(bc_type) ~= "string" then - return nil, "[ArgErr] 'bc_type' must be a string" - end - local pdash = string.find(bc_type, "-") - local family, variant - if pdash then - family = string.sub(bc_type, 1, pdash - 1) - variant = string.sub(bc_type, pdash + 1) - else - family = bc_type +-- retrive an encoder object already created +-- 'trename' is the special identifier of the encoder +function Barcode:enc_by_name(treename) --> <encoder object>, <err> + -- argument checking + local _family, _variant, _enc_name, err = parse_treename(treename) + if err then + return nil, err end - local av_enc = self._available_enc - if not av_enc[family] then -- is the barcode type a real module? - return nil, "[Err] barcode type '"..family.."' not found" - end - local builder = self._builder_instances[family] - if builder == nil then - return nil, "[Err] enc builder '"..family.."' not loaded, use 'new_encoder()' method" - end - if name == nil then - name = (variant or "") .. "_noname" - elseif type(name) ~= "string" then - return nil, "[ArgErr] 'name' must be a string" - end - local repo = builder._enc_instances - local enc = repo[name] - if enc == nil then - return nil, "[Err] encoder '"..name.."' not found" - else + local enc = self._encoder_instances[treename] + if enc then return enc, nil + else + return nil, "[Err] encoder '"..treename.."' not found" end end --- base constructors common to all the encoders +-- base methods common to all the encoders + -- for numeric only simbology function Barcode:_check_char(c) --> elem, err if type(c) ~= "string" or #c ~= 1 then @@ -260,19 +326,19 @@ function Barcode:_check_char(c) --> elem, err end return n, nil end +-- function Barcode:_check_digit(n) --> elem, err if type(n) ~= "number" then - return nil, "[InternalErr] not a number" + return nil, "[ArgErr] not a number" end if n < 0 or n > 9 then - return nil, "[InternalErr] not a digit" + return nil, "[ArgErr] not a digit" end return n, nil end -- not empty string --> Barcode object function Barcode:from_string(symb, opt) --> object, err - assert(self._check_char, "[InternalErr] undefined _check_char() method") if type(symb) ~= "string" then return nil, "[ArgErr] 'symb' is not a string" end @@ -281,11 +347,12 @@ function Barcode:from_string(symb, opt) --> object, err end local chars = {} local len = 0 + local parse_state = {} for c in string.gmatch(symb, ".") do - local elem, err = self:_check_char(c) + local elem, err = self:_check_char(c, parse_state) if err then return nil, err - else + elseif elem then chars[#chars+1] = elem len = len + 1 end @@ -307,7 +374,7 @@ function Barcode:from_string(symb, opt) --> object, err end end if o._finalize then - local ok, e = o:_finalize() + local ok, e = o:_finalize(parse_state) if not ok then return nil, e end end return o, nil @@ -315,9 +382,12 @@ end -- positive integer --> Barcode object function Barcode:from_uint(n, opt) --> object, err - assert(self._check_digit, "[InternalErr] undefined _check_digit() method") - if type(n) ~= "number" then return nil, "[ArgErr] 'n' is not a number" end - if n < 0 then return nil, "[ArgErr] 'n' must be a positive integer" end + if type(n) ~= "number" then + return nil, "[ArgErr] 'n' is not a number" + end + if n < 0 then + return nil, "[ArgErr] 'n' must be a positive integer" + end if n - math.floor(n) ~= 0 then return nil, "[ArgErr] 'n' is not an integer" end @@ -325,23 +395,28 @@ function Barcode:from_uint(n, opt) --> object, err return nil, "[ArgErr] 'opt' is not a table" end local digits = {} + local parse_state = {} local i = 0 if n == 0 then - local elem, err = self:_check_digit(0) + local elem, err = self:_check_digit(0, parse_state) if err then return nil, err end - digits[1] = elem - i = 1 + if elem then + digits[1] = elem + i = 1 + end else while n > 0 do local d = n % 10 - i = i + 1 - local elem, err = self:_check_digit(d) + local elem, err = self:_check_digit(d, parse_state) if err then return nil, err end - digits[i] = elem + if elem then + i = i + 1 + digits[i] = elem + end n = (n - d) / 10 end for k = 1, i/2 do -- reverse the array @@ -368,7 +443,7 @@ function Barcode:from_uint(n, opt) --> object, err end end if o._finalize then - local ok, e = o:_finalize() + local ok, e = o:_finalize(parse_state) if not ok then return nil, e end end return o, nil @@ -458,20 +533,29 @@ function Barcode:info() --> table param = {}, } local tpar = info.param - for _, pardef in self:param_ord_iter() do - local id = pardef.pname - local pdef = pardef.pdef + for _, pdef in self:param_ord_iter() do + local id = pdef.pname + local def = pdef.pdef tpar[#tpar + 1] = { name = id, descr = nil, -- TODO: value = self[id], - isReserved = pdef.isReserved, - unit = pdef.unit, + isReserved = def.isReserved, + unit = def.unit, } end return info end +-- return the code being represented as a string +-- or nil if the method is called from Barcode abstract class +function Barcode:get_code() --> string|nil + local code = self._code_data + if code then + return table.concat(code) + end +end + -- make accessible by name parameter values -- id: parameter identifier function Barcode:get_param(id) --> value, err @@ -509,11 +593,10 @@ function Barcode:set_param(arg1, arg2) --> boolean, err else return false, "[ArgErr] param name must be a string" end - -- preparing to the checking process + -- preparing the check process local cktab = {} local ckparam = {} - -- checking process - for _, tpar in self:param_ord_iter() do + for _, tpar in self:param_ord_iter() do -- checking process local pname = tpar.pname local pdef = tpar.pdef local val = targ[pname] -- par = val |