bool LocationIndex::VisitAdminRegionLocations(const AdminRegion& region,
                                                LocationVisitor& visitor,
                                                bool recursive) const
  {
    FileScanner scanner;
    bool        stopped=false;

    if (!scanner.Open(AppendFileToDir(path,
                                      FILENAME_LOCATION_IDX),
                      FileScanner::LowMemRandom,
                      true)) {
      log.Error() << "Cannot open file '" << scanner.GetFilename() << "'!";
      return false;
    }

    if (!scanner.SetPos(indexOffset)) {
      return false;
    }

    if (!scanner.SetPos(region.regionOffset)) {
      return false;
    }

    if (!VisitRegionLocationEntries(scanner,
                                    visitor,
                                    recursive,
                                    stopped)) {
      return false;
    }

    return !scanner.HasError() && scanner.Close();
  }
  bool LocationIndex::ResolveAdminRegionHierachie(const AdminRegionRef& adminRegion,
                                                  std::map<FileOffset,AdminRegionRef >& refs) const
  {
    FileScanner scanner;

    if (!scanner.Open(AppendFileToDir(path,
                                      FILENAME_LOCATION_IDX),
                      FileScanner::LowMemRandom,
                      true)) {
      log.Error() << "Cannot open file '" << scanner.GetFilename() << "'!";
      return false;
    }

    if (!scanner.SetPos(indexOffset)) {
      return false;
    }

    std::list<FileOffset> offsets;

    refs[adminRegion->regionOffset]=adminRegion;

    if (adminRegion->parentRegionOffset!=0) {
      offsets.push_back(adminRegion->parentRegionOffset);
    }

    while (!offsets.empty()) {
      std::list<FileOffset> newOffsets;

      for (const auto& offset : offsets) {
        if (refs.find(offset)!=refs.end()) {
          continue;
        }

        if (!scanner.SetPos(offset)) {
          return false;
        }

        AdminRegion adminRegion;

        if (!LoadAdminRegion(scanner,
                             adminRegion)) {
          return false;
        }

        refs[adminRegion.regionOffset]=std::make_shared<AdminRegion>(adminRegion);

        if (adminRegion.parentRegionOffset!=0) {
          newOffsets.push_back(adminRegion.parentRegionOffset);
        }

      }
      offsets.clear();

      std::swap(offsets,
                newOffsets);
    }

    return !scanner.HasError() && scanner.Close();
  }
  bool LocationIndex::VisitAdminRegions(AdminRegionVisitor& visitor) const
  {
    FileScanner scanner;

    if (!scanner.Open(AppendFileToDir(path,
                                      FILENAME_LOCATION_IDX),
                      FileScanner::LowMemRandom,
                      false)) {
      log.Error() << "Cannot open file '" << scanner.GetFilename() << "'!";
      return false;
    }

    if (!scanner.SetPos(indexOffset)) {
      return false;
    }

    uint32_t regionCount;

    if (!scanner.ReadNumber(regionCount)) {
      return false;
    }

    for (size_t i=0; i<regionCount; i++) {
      AdminRegionVisitor::Action action;
      FileOffset                 nextChildOffset;

      if (!scanner.ReadFileOffset(nextChildOffset)) {
        return false;
      }

      action=VisitRegionEntries(scanner,
                                visitor);

      if (action==AdminRegionVisitor::error) {
        return false;
      }
      else if (action==AdminRegionVisitor::stop) {
        return true;
      }
      else if (action==AdminRegionVisitor::skipChildren) {
        if (i+1<regionCount) {
          if (!scanner.SetPos(nextChildOffset)) {
            return false;
          }
        }
      }
    }

    return !scanner.HasError() && scanner.Close();
  }
  bool LocationIndex::VisitLocationAddressEntries(FileScanner& scanner,
                                                  const AdminRegion& region,
                                                  const Location& location,
                                                  AddressVisitor& visitor,
                                                  bool& stopped) const
  {
    uint32_t addressCount;

    if (!scanner.SetPos(location.addressesOffset)) {
      return false;
    }

    if (!scanner.ReadNumber(addressCount)) {
      return false;
    }

    ObjectFileRefStreamReader objectFileRefReader(scanner);

    for (size_t i=0; i<addressCount; i++) {
      Address address;

      if (!scanner.GetPos(address.addressOffset)) {
        return false;
      }

      address.locationOffset=location.locationOffset;
      address.regionOffset=location.regionOffset;

      if (!scanner.Read(address.name)) {
        return false;
      }

      if (!objectFileRefReader.Read(address.object)) {
        return false;
      }

      if (!visitor.Visit(region,
                         location,
                         address)) {
        stopped=true;

        break;
      }
    }

    return !scanner.HasError();
  }
  bool LocationIndex::VisitRegionLocationEntries(FileScanner& scanner,
                                                 LocationVisitor& visitor,
                                                 bool recursive,
                                                 bool& stopped) const
  {
    AdminRegion region;
    FileOffset       childrenOffset;
    uint32_t         childCount;

    if (!LoadAdminRegion(scanner,
                         region)) {
      return false;
    }

    if (!scanner.GetPos(childrenOffset)) {
      return false;
    }

    if (!scanner.SetPos(region.dataOffset)) {
      return false;
    }

    if (!LoadRegionDataEntry(scanner,
                             region,
                             visitor,
                             stopped)) {
      return false;
    }

    if (stopped || !recursive) {
      return !scanner.HasError();
    }

    if (!scanner.SetPos(childrenOffset)) {
      return false;
    }

    if (!scanner.ReadNumber(childCount)) {
      return false;
    }

    for (size_t i=0; i<childCount; i++) {
      FileOffset nextChildOffset;

      if (!scanner.ReadFileOffset(nextChildOffset)) {
        return false;
      }

      if (!VisitRegionLocationEntries(scanner,
                                      visitor,
                                      recursive,
                                      stopped)) {
        return false;
      }

      if (stopped) {
        break;
      }
    }

    return !scanner.HasError();
  }
  AdminRegionVisitor::Action LocationIndex::VisitRegionEntries(FileScanner& scanner,
                                                               AdminRegionVisitor& visitor) const
  {
    AdminRegion region;
    uint32_t    childCount;

    if (!LoadAdminRegion(scanner,
                         region)) {
      return AdminRegionVisitor::error;
    }

    AdminRegionVisitor::Action action=visitor.Visit(region);

    switch (action) {
    case AdminRegionVisitor::stop:
      return action;
    case AdminRegionVisitor::error:
      return action;
    case AdminRegionVisitor::skipChildren:
      return AdminRegionVisitor::skipChildren;
    case AdminRegionVisitor::visitChildren:
      // just continue...
      break;
    }

    if (!scanner.ReadNumber(childCount)) {
      return AdminRegionVisitor::error;
    }

    for (size_t i=0; i<childCount; i++) {
      FileOffset nextChildOffset;

      if (!scanner.ReadFileOffset(nextChildOffset)) {
        return AdminRegionVisitor::error;
      }

      action=VisitRegionEntries(scanner,
                                visitor);

      if (action==AdminRegionVisitor::stop ||
          action==AdminRegionVisitor::error) {
        return action;
      }
      else if (action==AdminRegionVisitor::skipChildren) {
        if (i+1<childCount) {
          if (!scanner.SetPos(nextChildOffset)) {
            return AdminRegionVisitor::error;
          }
        }
        else {
          return AdminRegionVisitor::skipChildren;
        }
      }
    }

    if (scanner.HasError()) {
      return AdminRegionVisitor::error;
    }
    else {
      return AdminRegionVisitor::visitChildren;
    }
  }