text: //========================================================================
  //
  // Linearization.cc
  //
  // This file is licensed under the GPLv2 or later
  //
  // Copyright 2010, 2012 Hib Eris <hib@hiberis.nl>
  // Copyright 2015 Jason Crain <jason@aquaticape.us>
  //
  //========================================================================
  
  #include "Linearization.h"
  #include "Parser.h"
  #include "Lexer.h"
  
  //------------------------------------------------------------------------
  // Linearization
  //------------------------------------------------------------------------
  
  Linearization::Linearization (BaseStream *str)
  {
    Parser *parser;
    Object obj1, obj2, obj3, obj5;
  
    linDict.initNull();
  
    str->reset();
    obj1.initNull();
    parser = new Parser(NULL,
        new Lexer(NULL, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)),
        gFalse);
    parser->getObj(&obj1);
    parser->getObj(&obj2);
    parser->getObj(&obj3);
    parser->getObj(&linDict);
    if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) {
      linDict.dictLookup("Linearized", &obj5);
      if (!(obj5.isNum() && obj5.getNum() > 0)) {
         linDict.free();
         linDict.initNull();
      }
      obj5.free();
    }
    obj3.free();
    obj2.free();
    obj1.free();
    delete parser;
  }
  
  Linearization:: ~Linearization()
  {
    linDict.free();
  }
  
  Guint Linearization::getLength()
  {
    if (!linDict.isDict()) return 0;
  
    int length;
    if (linDict.getDict()->lookupInt("L", NULL, &length) &&
        length > 0) {
      return length;
    } else {
      error(errSyntaxWarning, -1, "Length in linearization table is invalid");
      return 0;
    }
  }
  
  Guint Linearization::getHintsOffset()
  {
    int hintsOffset;
  
    Object obj1, obj2;
    if (linDict.isDict() &&
        linDict.dictLookup("H", &obj1)->isArray() &&
        obj1.arrayGetLength()>=2 &&
        obj1.arrayGet(0, &obj2)->isInt() &&
        obj2.getInt() > 0) {
      hintsOffset = obj2.getInt();
    } else {
      error(errSyntaxWarning, -1, "Hints table offset in linearization table is invalid");
      hintsOffset = 0;
    }
    obj2.free();
    obj1.free();
  
    return hintsOffset;
  }
  
  Guint Linearization::getHintsLength()
  {
    int hintsLength;
  
    Object obj1, obj2;
    if (linDict.isDict() &&
        linDict.dictLookup("H", &obj1)->isArray() &&
        obj1.arrayGetLength()>=2 &&
        obj1.arrayGet(1, &obj2)->isInt() &&
        obj2.getInt() > 0) {
      hintsLength = obj2.getInt();
    } else {
      error(errSyntaxWarning, -1, "Hints table length in linearization table is invalid");
      hintsLength = 0;
    }
    obj2.free();
    obj1.free();
  
    return hintsLength;
  }
  
  Guint Linearization::getHintsOffset2()
  {
    int hintsOffset2 = 0; // default to 0
  
    Object obj1, obj2;
    if (linDict.isDict() &&
        linDict.dictLookup("H", &obj1)->isArray() &&
        obj1.arrayGetLength()>=4) {
      if (obj1.arrayGet(2, &obj2)->isInt() &&
          obj2.getInt() > 0) {
        hintsOffset2 = obj2.getInt();
      } else {
        error(errSyntaxWarning, -1, "Second hints table offset in linearization table is invalid");
        hintsOffset2 = 0;
      }
    }
    obj2.free();
    obj1.free();
  
    return hintsOffset2;
  }
  
  Guint Linearization::getHintsLength2()
  {
    int hintsLength2 = 0; // default to 0
  
    Object obj1, obj2;
    if (linDict.isDict() &&
        linDict.dictLookup("H", &obj1)->isArray() &&
        obj1.arrayGetLength()>=4) {
      if (obj1.arrayGet(3, &obj2)->isInt() &&
          obj2.getInt() > 0) {
        hintsLength2 = obj2.getInt();
      } else {
        error(errSyntaxWarning, -1, "Second hints table length in linearization table is invalid");
        hintsLength2 = 0;
      }
    }
    obj2.free();
    obj1.free();
  
    return hintsLength2;
  }
  
  int Linearization::getObjectNumberFirst()
  {
    int objectNumberFirst = 0;
    if (linDict.isDict() &&
        linDict.getDict()->lookupInt("O", NULL, &objectNumberFirst) &&
        objectNumberFirst > 0) {
      return objectNumberFirst;
    } else {
      error(errSyntaxWarning, -1, "Object number of first page in linearization table is invalid");
      return 0;
    }
  }
  
  Guint Linearization::getEndFirst()
  {
    int pageEndFirst = 0;
    if (linDict.isDict() &&
        linDict.getDict()->lookupInt("E", NULL, &pageEndFirst) &&
        pageEndFirst > 0) {
      return pageEndFirst;
    } else {
      error(errSyntaxWarning, -1, "First page end offset in linearization table is invalid");
      return 0;
    }
  }
  
  int Linearization::getNumPages()
  {
    int numPages = 0;
    if (linDict.isDict() &&
        linDict.getDict()->lookupInt("N", NULL, &numPages) &&
        numPages > 0) {
      return numPages;
    } else {
      error(errSyntaxWarning, -1, "Page count in linearization table is invalid");
      return 0;
    }
  }
  
  Guint Linearization::getMainXRefEntriesOffset()
  {
    int mainXRefEntriesOffset = 0;
    if (linDict.isDict() &&
        linDict.getDict()->lookupInt("T", NULL, &mainXRefEntriesOffset) &&
        mainXRefEntriesOffset > 0) {
      return mainXRefEntriesOffset;
    } else {
      error(errSyntaxWarning, -1, "Main Xref offset in linearization table is invalid");
      return 0;
    }
  }
  
  int Linearization::getPageFirst()
  {
    int pageFirst = 0; // Optional, defaults to 0.
  
    if (linDict.isDict()) {
      linDict.getDict()->lookupInt("P", NULL, &pageFirst);
    }
  
    if ((pageFirst < 0) || (pageFirst >= getNumPages())) {
      error(errSyntaxWarning, -1, "First page in linearization table is invalid");
      return 0;
    }
  
    return pageFirst;
  }
  
  
  