create or replace function CalcMac(p_str in varchar2) return varchar2
is
  type arr_num is table of number(5) index by binary_integer;
  type arr_char is table of char(2) index by binary_integer;
  s_arr arr_char;
  Mac   arr_num;
  Len      number;
  Groupnum number;
  i        number;
  s_str    varchar2(4000);
  result   varchar2(4000);
  function fn_and(p_number1 int, p_number2 int) return integer is
    result integer;
  begin
    result := bitand(p_number1, p_number2);
    return result;
  end fn_and;  function fn_or(p_number1 int, p_number2 int) return integer is
    result integer;
  begin
    result := p_number1 - bitand(p_number1, p_number2) + p_number2;
    return result;
  end fn_or;  function fn_xor(p_number1 int, p_number2 int) return integer is
    result integer;
  begin
    result := (p_number1 - bitand(p_number1, p_number2)) + (p_number2 - bitand(p_number1, p_number2));
    return result;
  end fn_xor;
begin
  Len := lengthb(p_str);
  Groupnum := trunc(Len / 4);
  if (Len mod 4) <> 0 then
    Groupnum := Groupnum + 1;
  end if;  Mac(1) := 0;
  Mac(2) := 0;
  Mac(3) := 0;
  Mac(4) := 0;  --转换为16进制
  for i in 1..length(p_str) loop
    s_str := s_str || trim(to_char(ascii(substr(p_str, i, 1)), 'xxxx'));
  end loop;
  
  for i in 1..length(s_str)/2 loop
      s_arr(i) := substr(s_str, 1, 2);
      s_str := substr(s_str, 3, length(s_str));
  end loop;
  
  for i in 1..Groupnum loop
    if (i - 1) * 4 + 1 <= Len then
      Mac(1) := fn_xor(Mac(1), to_number(s_arr((i - 1) * 4 + 1), 'xxx')); 
    end if;
    if (i - 1) * 4 + 2 <= Len then
      Mac(2) := fn_xor(Mac(2), to_number(s_arr((i - 1) * 4 + 2), 'xxx'));
    end if;
    if (i - 1) * 4 + 3 <= Len then
      Mac(3) := fn_xor(Mac(3), to_number(s_arr((i - 1) * 4 + 3), 'xxx'));
    end if;
    if (i - 1) * 4 + 4 <= Len then
      Mac(4) := fn_xor(Mac(4), to_number(s_arr((i - 1) * 4 + 4), 'xxx'));
    end if;
  end loop;
  result := '';
  result := result||chr(trunc(mac(1)/16) + 48);
  result := result||chr(fn_and(mac(1), 15) + 48);
  result := result||chr(trunc(mac(2)/16) + 48);
  result := result||chr(fn_and(mac(2), 15) + 48);
  result := result||chr(trunc(mac(3)/16) + 48);
  result := result||chr(fn_and(mac(3), 15) + 48);
  result := result||chr(trunc(mac(4)/16) + 48);
  result := result||chr(fn_and(mac(4), 15) + 48);
  return result;
end CalcMac;
能否改进一下,这个是我初步写的,对数据包进行MAC校验的
各位高手帮忙改进一下,谢谢!