% Copyright (C) 2001-2023 Artifex Software, Inc.
% All Rights Reserved.
%
% This software is provided AS-IS with no warranty, either express or
% implied.
%
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
%
% Refer to licensing information at http://www.artifex.com or contact
% Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
% CA 94129, USA, for further information.
%

% Define SubstCID, Decoding and CIDDecoding resource categories and related procsets.

languagelevel 2 .setlanguagelevel
currentglobal //true setglobal

%----------------ParseDecoding procset----------------------------

/ParseDecoding <<

/Parse    % <resource_name> <num_tokens> Parse -
{ dict begin                                  % /ResName
  0                                           % /ResName nCode
  { currentfile token not {
      exit
    } if                                      % /ResName nCode token
    dup type /integertype eq {                % /ResName nCode
       exch pop
    } {
      1 index def                             % /ResName nCode
    } ifelse
  } loop                                      % /ResName nCode
  pop                                         % /ResName
  currentdict end /Decoding                   % /ResName <<inst>> /Decoding
  defineresource pop
} .internalbind

>> /ProcSet defineresource pop

%----------------Decoding category----------------------------

/Generic /Category findresource dup length dict copy
dup /InstanceType /dicttype put
/Decoding exch /Category defineresource pop

%----------------ParseCMap_Inverse procset----------------------------

/ParseCMap_Inverse <<
  /findresource { pop } .internalbind
  /defineresource { pop pop } .internalbind
  /dict {}
  /def { pop pop } .internalbind
  /dup //null
  /begin { pop } .internalbind
  /end {}
  /currentdict //null
  /CMapName //null
  /usecmap { pop } .internalbind
  /begincmap {}
  /endcmap {}
  /begincodespacerange { pop mark } .internalbind
  /endcodespacerange { cleartomark } .internalbind
  /beginnotdefrange { pop mark } .internalbind
  /endnotdefrange { cleartomark } .internalbind
  /beginbfchar { pop mark } .internalbind
  /endbfchar { pop mark } .internalbind
  /beginbfrange { begincidrange }
  /endbfrange { endcidrange }
  /begincidchar { beginbfchar }
  /endcidchar { endbfchar }
  /begincidrange { pop mark } .internalbind
  /endcidrange  { cleartomark } .internalbind
>>  % Just keep it on stack for a while.

% Now we define another dict for local .internalbinding, than merge it with the previous one :
dup length 5 add dict begin

  /.Ranges 40 dict def % Key = CID/256, value = array of 256 integer codes.
  //.Ranges /CIDCount 0 put

  /.StringToInt     % <string> .StringToInt <integer>
  { 0 exch { exch 8 bitshift add } forall
  } .internalbind def

  /.SetCouple    % <I> <b> .SetCouple -
  { exch                                    % b I
    dup 256 idiv                            % b I I0
    dup //.Ranges exch known not {
      dup //.Ranges exch 256 array put
    } if                                    % b I I0
    //.Ranges exch get                      % b I [Range]
    exch 256 mod                            % b [Range] I1
    2 copy get                              % b [Range] I1 e
    dup //null ne {
      % We've got char code duplicates for same CID.
      dup type /integertype eq {
        4 3 roll                            % [Range] I1 e b
        2 array astore put                  %
      } {
        dup length 1 add dup dup array dup  % b [Range] I1 D l l D' D'
        3 2 roll 0 exch getinterval         % b [Range] I1 D l D' D''
        4 3 roll exch copy pop              % b [Range] I1 l D'
        dup 3 2 roll 1 sub                  % b [Range] I1 D' D' l-1
        6 5 roll                            % [Range] I1 D' D' l-1 b
        put put                             %
      } ifelse
    } {
      pop 3 2 roll put                      %
    } ifelse
  } .internalbind def

  /endcidrange
  { % Writes the inversed CMap to .Ranges
    counttomark 3 idiv {                    % (b) (e) I
      exch .StringToInt                     % (b) I e
      3 2 roll .StringToInt                 % I e b
      % Note : this code does't handle multidimentional CID ranges.
      % fixme : optimize below.
      dup 3 2 roll exch sub 1 add           % I b d
      { 2 copy //.SetCouple exec            % I b
        1 add exch 1 add exch
      } repeat                              % I b
      pop                                   % I
      dup //.Ranges /CIDCount get gt {      % I
        dup //.Ranges exch /CIDCount exch put
      } if                                  % I
      pop
    } repeat
    pop % mark
  } .internalbind def

  /.GetCIDDecoding         % - .GetCIDDEcoding <dict>
  { //.Ranges dup length dict copy
    //.Ranges //.PurgeDict exec
    //.Ranges /CIDCount 0 put
  } .internalbind def

currentdict end
exch copy % Merge the dicts - see above.
/ProcSet defineresource pop

%----------------CIDDecoding category----------------------------
% Note that we put all instances in global memory - see FindResource.

/Generic /Category findresource dup length dict copy
begin
  /Category /CIDDecoding def
  /InstanceType /dicttype def

  /.CMapChooser <<
    % This lists CMaps to inverse and unite for creating a CIDDecoding.
    % Choose by FAPIcidfmap.Registry concatenated with TrueType encoding ID.
    % Font renderer must provide the glyph substitution internally.

    /CNS1.Big5       [ /ETen-B5-H /ETen-B5-V ]
    /CNS1.Unicode    [ /UniCNS-UCS2-H /UniCNS-UCS2-V]
    /CNS1.UCS-4    [ /UniCNS-UCS2-H /UniCNS-UCS2-V]
    /GB1.GB2312      [ /GBK-EUC-H /GBK-EUC-V ]
    /GB1.Unicode     [ /UniGB-UCS2-H /UniGB-UCS2-V ]
    /GB1.UCS-4     [ /UniGB-UCS2-H /UniGB-UCS2-V ]
    /Japan1.ShiftJIS [ /90ms-RKSJ-H /90ms-RKSJ-V ]
    /Japan1.Unicode  [ /UniJIS-UCS2-H  /UniJIS-UCS2-V]
    /Japan1.UCS-4  [ /UniJIS-UCS2-H  /UniJIS-UCS2-V]
    /Japan2.ShiftJIS [ /90ms-RKSJ-H /90ms-RKSJ-V ]
    /Japan2.Unicode  [ /UniHojo-UCS2-H ]
    /Japan2.UCS-4    [ /UniHojo-UCS2-H ]
    /Korea1.Johab    [ /KSC-Johab-V /KSC-Johab-H ]
    /Korea1.Wansung  [ /KSCms-UHC-V /KSCms-UHC-H ]
    /Korea1.Unicode  [ /UniKS-UCS2-H /UniKS-UCS2-V ]
    /Identity.Symbol [ /Identity-H /Identity-V ]
    /Unicode.Unicode [ /Identity-UTF16-H ]
    /Identity.Unicode [ /Identity-UTF16-H ]
    /Identity.UCS-4 [ /Identity-H /Identity-V ]
  >> def

  /.MakeInstance    % <name> .MakeInstance <inst>
  { dup                                              % /Name /Name
    //.CMapChooser exch .knownget not {
      (Can't build /) print =string cvs print
      ( /CIDDecoding resource. See gs_ciddc.ps . ) = flush
      /findresource cvx /undefinedresource signalerror
    } if                                             % /Name [CMaps]
    exch pop                                         % [CMaps]
    /CMap /Category findresource                     % [CMaps] <CMapCategory>
    /ParseCMap_Inverse /ProcSet findresource         % [CMaps] <CMapCategory> <PCI>
    3 2 roll {                                       % <CMapCategory> <PCI> /CMapName
      3 2 roll begin                                 % <PCI> /CMapName
      dup .ResourceFile not {
        (Can't find CMap ) print =string cvs print
        ( building a CIDDecoding resource. ) = flush
        /findresource cvx /undefinedresource signalerror
      } if
      currentdict end exch                           % <PCI> /CMapName <CMapCategory> file

      3 index begin
      cvx exec                                       % <PCI> /CMapName <CMapCategory>
      end
      exch pop exch                                  % <CMapCategory> <PCI>
    } forall
    exch pop begin                                   %
    .GetCIDDecoding
    end
  } .internalbind def

  /FindResource      % <name> FindResource <dict>
  { currentglobal exch                               % bGlobal /InstName
    //true setglobal
    dup //.MakeInstance exec                         % bGlobal /InstName <Inst>
    DefineResource                                   % bGlobal <Inst>
    exch setglobal                                   % <Inst>
  } .internalbind def

currentdict end
/CIDDecoding exch /Category defineresource pop

%----------------SubstCID category----------------------------

/Generic /Category findresource dup length dict copy
begin
  /Category /SubstCID def
  /InstanceType /dicttype def
currentdict end
/SubstCID exch /Category defineresource pop

setglobal
.setlanguagelevel
