"Fossies" - the Fresh Open Source Software Archive

Member "poppler-0.82.0/poppler/PageLabelInfo.cc" (25 Oct 2019, 5461 Bytes) of package /linux/misc/poppler-0.82.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "PageLabelInfo.cc" see the Fossies "Dox" file reference documentation.

    1 //========================================================================
    2 //
    3 // This file is under the GPLv2 or later license
    4 //
    5 // Copyright (C) 2005-2006 Kristian Høgsberg <krh@redhat.com>
    6 // Copyright (C) 2005, 2009, 2013, 2017, 2018 Albert Astals Cid <aacid@kde.org>
    7 // Copyright (C) 2011 Simon Kellner <kellner@kit.edu>
    8 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
    9 // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
   10 //
   11 // To see a description of the changes please see the Changelog file that
   12 // came with your tarball or type make ChangeLog if you are building from git
   13 //
   14 //========================================================================
   15 
   16 #include <config.h>
   17 #include <limits.h>
   18 #include <stdlib.h>
   19 #include <stdio.h>
   20 #include <assert.h>
   21 
   22 #include <algorithm>
   23 
   24 #include "PageLabelInfo.h"
   25 #include "PageLabelInfo_p.h"
   26 
   27 PageLabelInfo::Interval::Interval(Object *dict, int baseA) {
   28   style = None;
   29   Object obj = dict->dictLookup("S");
   30   if (obj.isName()) {
   31     if (obj.isName("D")) {
   32       style = Arabic;
   33     } else if (obj.isName("R")) {
   34       style = UppercaseRoman;
   35     } else if (obj.isName("r")) {
   36       style = LowercaseRoman;
   37     } else if (obj.isName("A")) {
   38       style = UppercaseLatin;
   39     } else if (obj.isName("a")) {
   40       style = LowercaseLatin;
   41     }
   42   }
   43 
   44   obj = dict->dictLookup("P");
   45   if (obj.isString()) {
   46     const auto str = obj.getString();
   47     prefix.assign(str->c_str(), str->getLength());
   48   }
   49 
   50   obj = dict->dictLookup("St");
   51   if (obj.isInt())
   52     first = obj.getInt();
   53   else
   54     first = 1;
   55 
   56   base = baseA;
   57 }
   58 
   59 PageLabelInfo::PageLabelInfo(Object *tree, int numPages) {
   60   parse(tree);
   61 
   62   if (intervals.empty())
   63     return;
   64 
   65   auto curr = intervals.begin();
   66   for(auto next = curr + 1; next != intervals.end(); ++next, ++curr) {
   67     curr->length = std::max(0, next->base - curr->base);
   68   }
   69   curr->length = std::max(0, numPages - curr->base);
   70 }
   71 
   72 void PageLabelInfo::parse(Object *tree) {
   73   // leaf node
   74   Object nums = tree->dictLookup("Nums");
   75   if (nums.isArray()) {
   76     for (int i = 0; i < nums.arrayGetLength(); i += 2) {
   77       Object obj = nums.arrayGet(i);
   78       if (!obj.isInt()) {
   79     continue;
   80       }
   81       int base = obj.getInt();
   82       obj = nums.arrayGet(i + 1);
   83       if (!obj.isDict()) {
   84     continue;
   85       }
   86 
   87       intervals.emplace_back(&obj, base);
   88     }
   89   }
   90 
   91   Object kids = tree->dictLookup("Kids");
   92   if (kids.isArray()) {
   93     for (int i = 0; i < kids.arrayGetLength(); ++i) {
   94       Object kid = kids.arrayGet(i);
   95       if (kid.isDict())
   96     parse(&kid);
   97     }
   98   }
   99 }
  100 
  101 bool PageLabelInfo::labelToIndex(GooString *label, int *index) const
  102 {
  103   const char *const str = label->c_str();
  104   const std::size_t strLen = label->getLength();
  105   const bool strUnicode = label->hasUnicodeMarker();
  106   int number;
  107   bool ok;
  108 
  109   for (const auto& interval : intervals) {
  110     const std::size_t prefixLen = interval.prefix.size();
  111     if (strLen < prefixLen || interval.prefix.compare(0, prefixLen, str, prefixLen) != 0)
  112       continue;
  113 
  114     switch (interval.style) {
  115     case Interval::Arabic:
  116       std::tie(number, ok) = fromDecimal(str + prefixLen, str + strLen, strUnicode);
  117       if (ok && number - interval.first < interval.length) {
  118     *index = interval.base + number - interval.first;
  119     return true;
  120       }
  121       break;
  122     case Interval::LowercaseRoman:
  123     case Interval::UppercaseRoman:
  124       number = fromRoman(str + prefixLen);
  125       if (number >= 0 && number - interval.first < interval.length) {
  126     *index = interval.base + number - interval.first;
  127     return true;
  128       }
  129       break;
  130     case Interval::UppercaseLatin:
  131     case Interval::LowercaseLatin:
  132       number = fromLatin(str + prefixLen);
  133       if (number >= 0 && number - interval.first < interval.length) {
  134     *index = interval.base + number - interval.first;
  135     return true;
  136       }
  137       break;
  138     case Interval::None:
  139       break;
  140     }
  141   }
  142 
  143   return false;
  144 }
  145 
  146 bool PageLabelInfo::indexToLabel(int index, GooString *label) const
  147 {
  148   char buffer[32];
  149   int base, number;
  150   const Interval *matching_interval;
  151   GooString number_string;
  152 
  153   base = 0;
  154   matching_interval = nullptr;
  155   for (const auto& interval : intervals) {
  156     if (base <= index && index < base + interval.length) {
  157       matching_interval = &interval;
  158       break;
  159     }
  160     base += interval.length;
  161   }
  162 
  163   if (!matching_interval)
  164     return false;
  165 
  166   number = index - base + matching_interval->first;
  167   switch (matching_interval->style) {
  168   case Interval::Arabic:
  169     snprintf (buffer, sizeof(buffer), "%d", number);
  170     number_string.append(buffer);
  171     break;
  172   case Interval::LowercaseRoman:
  173     toRoman(number, &number_string, false);
  174     break;
  175   case Interval::UppercaseRoman:
  176     toRoman(number, &number_string, true);
  177     break;
  178   case Interval::LowercaseLatin:
  179     toLatin(number, &number_string, false);
  180     break;
  181   case Interval::UppercaseLatin:
  182     toLatin(number, &number_string, true);
  183     break;
  184   case Interval::None:
  185     break;
  186   }
  187 
  188   label->clear();
  189   label->append(matching_interval->prefix.c_str(), matching_interval->prefix.size());
  190   if (label->hasUnicodeMarker()) {
  191       int i, len;
  192       char ucs2_char[2];
  193 
  194       /* Convert the ascii number string to ucs2 and append. */
  195       len = number_string.getLength ();
  196       ucs2_char[0] = 0;
  197       for (i = 0; i < len; ++i) {
  198       ucs2_char[1] = number_string.getChar(i);
  199       label->append(ucs2_char, 2);
  200       }
  201   } else {
  202       label->append(&number_string);
  203   }
  204 
  205   return true;
  206 }