--[[ Copyright (c) 2012-2013 Kaarle Ritvanen See LICENSE file for license details --]] local M = {} local raise = require('acf2.error').raise local Union = require('acf2.model.combination').Union local fld = require('acf2.model.field') local String = fld.String local object = require('acf2.object') local class = object.class local super = object.super local update = require('acf2.util').update local stringy = require('stringy') M.IPv4Address = class(String) function M.IPv4Address:validate(context, value) super(self, M.IPv4Address):validate(context, value) local function test(...) if #{...} ~= 4 then return true end for _, octet in ipairs{...} do if tonumber(octet) > 255 then return true end end end if test(value:match('^(%d+)%.(%d+)%.(%d+)%.(%d+)$')) then raise(context.path, 'Invalid IPv4 address') end end M.IPv6Address = class(String) function M.IPv6Address:validate(context, value) super(self, M.IPv6Address):validate(context, value) local function invalid() raise(context.path, 'Invalid IPv6 address') end if value == '' then invalid() end local comps = stringy.split(value, ':') if #comps < 3 then invalid() end local function collapse(i, ofs) if comps[i] > '' then return end if comps[i + ofs] > '' then invalid() end table.remove(comps, i) end collapse(1, 1) collapse(#comps, -1) if #comps > 8 then invalid() end local short = false for _, comp in ipairs(comps) do if comp == '' then if short then invalid() end short = true elseif not comp:match('^%x%x?%x?%x?$') then invalid() end end if ( short and #comps == 3 and comps[2] == '' ) or (not short and #comps < 8) then invalid() end end M.IPAddress = class(Union) function M.IPAddress:init(params) super(self, M.IPAddress):init( update( params, {types={M.IPv4Address, M.IPv6Address}, error='Invalid IP address'} ) ) end M.Port = class(fld.Integer) function M.Port:validate(context, value) super(self, M.Port):validate(context, value) if value < 0 or value > 65535 then raise(context.path, 'Invalid port') end end return M