<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/printing/print_preview_message_handler.h"

#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/webui/print_preview_handler.h"
#include "chrome/browser/webui/print_preview_ui.h"
#include "chrome/browser/webui/print_preview_ui_html_source.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "ipc/ipc_message_macros.h"

namespace printing {

PrintPreviewMessageHandler::PrintPreviewMessageHandler(
    TabContents* tab_contents)
    : TabContentsObserver(tab_contents) {
  DCHECK(tab_contents);
}

PrintPreviewMessageHandler::~PrintPreviewMessageHandler() {
}

TabContents* PrintPreviewMessageHandler::GetPrintPreviewTab() {
  // Get/Create preview tab for initiator tab.
  printing::PrintPreviewTabController* tab_controller =
      printing::PrintPreviewTabController::GetInstance();
  if (!tab_controller)
    return NULL;
  return tab_controller->GetPrintPreviewForTab(tab_contents());
}

void PrintPreviewMessageHandler::OnPagesReadyForPreview(
    const ViewHostMsg_DidPreviewDocument_Params& params) {
#if defined(OS_POSIX)
  base::SharedMemory* shared_buf =
      new base::SharedMemory(params.metafile_data_handle, true);
  if (!shared_buf->Map(params.data_size)) {
    NOTREACHED();
    return;
  }
#endif

  // Get the print preview tab.
  TabContents* print_preview_tab = GetPrintPreviewTab();
  DCHECK(print_preview_tab);

#if defined(OS_POSIX)
  PrintPreviewUI* print_preview_ui =
      static_cast<PrintPreviewUI*>(print_preview_tab->web_ui());
  print_preview_ui->html_source()->SetPrintPreviewData(
      std::make_pair(shared_buf, params.data_size));
  print_preview_ui->PreviewDataIsAvailable(params.expected_pages_count);
#endif

  scoped_refptr<printing::PrinterQuery> printer_query;
  g_browser_process->print_job_manager()->PopPrinterQuery(
      params.document_cookie, &printer_query);
  if (printer_query.get()) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(printer_query.get(),
                          &printing::PrinterQuery::StopWorker));
  }

  RenderViewHost* rvh = tab_contents()->render_view_host();
  rvh->Send(new ViewMsg_PrintingDone(rvh->routing_id(),
                                     params.document_cookie,
                                     true));
}

bool PrintPreviewMessageHandler::OnMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message)
    IPC_MESSAGE_HANDLER(ViewHostMsg_PagesReadyForPreview,
                        OnPagesReadyForPreview)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

}  // namespace printing
<commit_msg>Print Preview: Add some CHECKs to help track down a crash.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/printing/print_preview_message_handler.h"

#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/webui/print_preview_handler.h"
#include "chrome/browser/webui/print_preview_ui.h"
#include "chrome/browser/webui/print_preview_ui_html_source.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "ipc/ipc_message_macros.h"

namespace printing {

PrintPreviewMessageHandler::PrintPreviewMessageHandler(
    TabContents* tab_contents)
    : TabContentsObserver(tab_contents) {
  DCHECK(tab_contents);
}

PrintPreviewMessageHandler::~PrintPreviewMessageHandler() {
}

TabContents* PrintPreviewMessageHandler::GetPrintPreviewTab() {
  // Get/Create preview tab for initiator tab.
  printing::PrintPreviewTabController* tab_controller =
      printing::PrintPreviewTabController::GetInstance();
  if (!tab_controller)
    return NULL;
  return tab_controller->GetPrintPreviewForTab(tab_contents());
}

void PrintPreviewMessageHandler::OnPagesReadyForPreview(
    const ViewHostMsg_DidPreviewDocument_Params& params) {
#if defined(OS_POSIX)
  base::SharedMemory* shared_buf =
      new base::SharedMemory(params.metafile_data_handle, true);
  if (!shared_buf->Map(params.data_size)) {
    NOTREACHED();
    return;
  }
#endif

  // Get the print preview tab.
  TabContents* print_preview_tab = GetPrintPreviewTab();
  DCHECK(print_preview_tab);

#if defined(OS_POSIX)
  PrintPreviewUI* print_preview_ui =
      static_cast<PrintPreviewUI*>(print_preview_tab->web_ui());
  PrintPreviewUIHTMLSource* html_source = print_preview_ui->html_source();
  CHECK(html_source);
  html_source->SetPrintPreviewData(
      std::make_pair(shared_buf, params.data_size));
  print_preview_ui->PreviewDataIsAvailable(params.expected_pages_count);
#endif

  PrintJobManager* print_job_manager = g_browser_process->print_job_manager();
  CHECK(print_job_manager);
  scoped_refptr<printing::PrinterQuery> printer_query;
  print_job_manager->PopPrinterQuery(params.document_cookie, &printer_query);
  if (printer_query.get()) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(printer_query.get(),
                          &printing::PrinterQuery::StopWorker));
  }

  RenderViewHost* rvh = tab_contents()->render_view_host();
  rvh->Send(new ViewMsg_PrintingDone(rvh->routing_id(),
                                     params.document_cookie,
                                     true));
}

bool PrintPreviewMessageHandler::OnMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message)
    IPC_MESSAGE_HANDLER(ViewHostMsg_PagesReadyForPreview,
                        OnPagesReadyForPreview)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

}  // namespace printing
<|endoftext|>


<commit_before>/* cclive
 * Copyright (C) 2013  Toni Gundogdu <legatvs@gmail.com>
 *
 * This file is part of cclive <http://cclive.sourceforge.net/>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <ccinternal>

#include <curl/curl.h>

#include <ccquvi>
#include <ccoptions>
#include <ccutil>

namespace cc
{

namespace po = boost::program_options;

static void _set_proxy(CURL *c, const po::variables_map& map)
{
  if (map.count("proxy"))
    {
      curl_easy_setopt(c, CURLOPT_PROXY,
                       map["proxy"].as<std::string>().c_str());
    }

  if (opts.flags.no_proxy)
    curl_easy_setopt(c, CURLOPT_PROXY, "");
}

void curl_setup(CURL *c)
{
  const po::variables_map map = cc::opts.map();

  if (map.count("throttle"))
    {
      curl_off_t limit = map["throttle"].as<int>()*1024;
      curl_easy_setopt(c, CURLOPT_MAX_RECV_SPEED_LARGE, limit);
    }

  curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L);

  if (cc::opts.flags.verbose_libcurl)
    curl_easy_setopt(c, CURLOPT_VERBOSE, 1L);

  curl_easy_setopt(c, CURLOPT_USERAGENT,
                   map["agent"].as<std::string>().c_str());

  curl_easy_setopt(c, CURLOPT_DNS_CACHE_TIMEOUT,
                   map["dns-cache-timeout"].as<int>());

  curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT,
                   map["connect-timeout"].as<int>());

  curl_easy_setopt(c, CURLOPT_TIMEOUT,
                   map["transfer-timeout"].as<int>());

  _set_proxy(c, map);
}

} // namespace cc

// vim: set ts=2 sw=2 tw=72 expandtab:
<commit_msg>cc: curl_setup: Set CURLOPT_USERAGENT if libquvi 0.4<commit_after>/* cclive
 * Copyright (C) 2013  Toni Gundogdu <legatvs@gmail.com>
 *
 * This file is part of cclive <http://cclive.sourceforge.net/>.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <ccinternal>

#include <curl/curl.h>

#include <ccquvi>
#include <ccoptions>
#include <ccutil>

namespace cc
{

namespace po = boost::program_options;

static void _set_proxy(CURL *c, const po::variables_map& map)
{
  if (map.count("proxy"))
    {
      curl_easy_setopt(c, CURLOPT_PROXY,
                       map["proxy"].as<std::string>().c_str());
    }

  if (opts.flags.no_proxy)
    curl_easy_setopt(c, CURLOPT_PROXY, "");
}

void curl_setup(CURL *c)
{
  const po::variables_map map = cc::opts.map();

  if (map.count("throttle"))
    {
      curl_off_t limit = map["throttle"].as<int>()*1024;
      curl_easy_setopt(c, CURLOPT_MAX_RECV_SPEED_LARGE, limit);
    }

  curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L);

  if (cc::opts.flags.verbose_libcurl)
    curl_easy_setopt(c, CURLOPT_VERBOSE, 1L);

#ifndef HAVE_LIBQUVI_0_9
  curl_easy_setopt(c, CURLOPT_USERAGENT,
                   map["agent"].as<std::string>().c_str());
#endif

  curl_easy_setopt(c, CURLOPT_DNS_CACHE_TIMEOUT,
                   map["dns-cache-timeout"].as<int>());

  curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT,
                   map["connect-timeout"].as<int>());

  curl_easy_setopt(c, CURLOPT_TIMEOUT,
                   map["transfer-timeout"].as<int>());

  _set_proxy(c, map);
}

} // namespace cc

// vim: set ts=2 sw=2 tw=72 expandtab:
<|endoftext|>


<commit_before><commit_msg>isfinite is supposed to be a macro for both double and float<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2012 Bram van der Kroef
 *
 * This file is part of LESS CSS Compiler.
 *
 * LESS CSS Compiler is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LESS CSS Compiler is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LESS CSS Compiler.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Bram van der Kroef <bram@vanderkroef.net>
 */

#include "LessParser.h"
#include <config.h>

#ifdef WITH_LIBGLOG
#include <glog/logging.h>
#endif

#include <libgen.h>

/**
 * Only allows LessStylesheets
 */
void LessParser::parseStylesheet(LessStylesheet &stylesheet) {
#ifdef WITH_LIBGLOG
  VLOG(1) << "Parser Start";
#endif

  CssParser::parseStylesheet(stylesheet);

#ifdef WITH_LIBGLOG
  VLOG(1) << "Parser End";
#endif
}

void LessParser::skipWhitespace () {
  while (tokenizer->getTokenType() == Token::WHITESPACE ||
         (tokenizer->getTokenType() == Token::COMMENT &&
          tokenizer->getToken().compare(0, 2, "//") == 0)) {
    tokenizer->readNextToken();
  }
}

bool LessParser::parseStatement(Stylesheet &stylesheet) {
  Selector selector;
  Mixin* mixin;
  CssComment* comment;
  LessStylesheet* ls = (LessStylesheet*)&stylesheet;

  if (tokenizer->getTokenType() == Token::COMMENT) {
    comment = ls->createComment();
    comment->setComment(tokenizer->getToken());
    tokenizer->readNextToken();
    skipWhitespace();
    return true;
  } else if (parseSelector(selector) && !selector.empty()) {
#ifdef WITH_LIBGLOG
    VLOG(2) << "Parse: Selector: " << selector.toString();
#endif

    if (parseRuleset(*ls, selector))
      return true;

    // Parameter mixin in the root. Inserts nested rules but no
    // declarations.
    mixin = ls->createMixin();
    mixin->setReference(reference);

    if (mixin->parse(selector)) {
      if (tokenizer->getTokenType() == Token::DELIMITER) {
        tokenizer->readNextToken();
        skipWhitespace();
      }
      return true;
    } else {
      ls->deleteMixin(*mixin);
      throw new ParseException(tokenizer->getToken(),
                               "a declaration block ('{...}') following selector");
    }

  } else {
    return parseAtRuleOrVariable(*ls);
  }
}

bool LessParser::parseAtRuleOrVariable (LessStylesheet &stylesheet) {
  Token token;
  TokenList value, rule;
  AtRule* atrule = NULL;

  if (tokenizer->getTokenType() != Token::ATKEYWORD)
    return false;

  token = tokenizer->getToken();
  tokenizer->readNextToken();
  CssParser::skipWhitespace();

#ifdef WITH_LIBGLOG
  VLOG(2) << "Parse: keyword: " << token;
#endif

  if (parseVariable(value)) {
#ifdef WITH_LIBGLOG
    VLOG(2) << "Parse: variable";
#endif
    stylesheet.putVariable(token, value);

  } else {
    if (token == "@media") {
      parseLessMediaQuery(token, stylesheet);
      return true;
    }

    while(parseAny(rule)) {};

    if (!parseBlock(rule)) {
      if (tokenizer->getTokenType() != Token::DELIMITER) {
        throw new ParseException(tokenizer->getToken(),
                                 "delimiter (';') at end of @-rule");
      }
      tokenizer->readNextToken();
      skipWhitespace();
    }
    // parse import
    if (token == "@import" && rule.size() > 0) {
      if (parseImportStatement(rule, stylesheet))
        return true;
    }

    atrule = stylesheet.createLessAtRule(token);
    atrule->setReference(reference);
    atrule->setRule(rule);
  }
  return true;
}

bool LessParser::parseVariable (TokenList &value) {
  if (tokenizer->getTokenType() != Token::COLON)
    return false;

  tokenizer->readNextToken();
  CssParser::skipWhitespace();

  if (parseValue(value) == false || value.size() == 0) {
    throw new ParseException(tokenizer->getToken(),
                             "value for variable");
  }
  if (tokenizer->getTokenType() != Token::DELIMITER) {
    throw new ParseException(tokenizer->getToken(),
                             "delimiter (';') at end of @-rule");
  }
  tokenizer->readNextToken();
  skipWhitespace();

  return true;
}

bool LessParser::parseSelector(Selector &selector) {
  if (!parseAny(selector))
    return false;

  while (parseAny(selector) || parseSelectorVariable(selector)) {};

  // delete trailing whitespace
  selector.rtrim();
  return true;
}

bool LessParser::parseSelectorVariable(Selector &selector) {
  Token* back;

  if (tokenizer->getTokenType() == Token::BRACKET_OPEN) {
    back = &selector.back();

    if (back->at(back->length() - 1) == '@') {
      back->append(tokenizer->getToken());

      if (tokenizer->readNextToken() != Token::IDENTIFIER)
        throw new ParseException(tokenizer->getToken(),
                                 "Variable inside selector (e.g.: \
@{identifier})");
      back->append(tokenizer->getToken());

      if (tokenizer->readNextToken() != Token::BRACKET_CLOSED)
        throw new ParseException(tokenizer->getToken(),
                                 "Closing bracket after variable.");

      back->append(tokenizer->getToken());
      tokenizer->readNextToken();

      parseWhitespace(selector);

      return true;
    }
  }
  return false;
}

bool LessParser::parseRuleset (LessStylesheet &stylesheet,
                               Selector &selector,
                               LessRuleset* parent) {
  LessRuleset* ruleset;

  if (tokenizer->getTokenType() != Token::BRACKET_OPEN)
    return false;

  tokenizer->readNextToken();
  skipWhitespace();

#ifdef WITH_LIBGLOG
  VLOG(2) << "Parse: Ruleset";
#endif

  // Create the ruleset and parse ruleset statements.
  if (parent == NULL)
    ruleset = stylesheet.createLessRuleset();
  else
    ruleset = parent->createNestedRule();
  ruleset->setReference(reference);
  ruleset->setSelector(selector);

  parseRulesetStatements(stylesheet, *ruleset);

  if (tokenizer->getTokenType() != Token::BRACKET_CLOSED) {
    throw new ParseException(tokenizer->getToken(),
                             "end of declaration block ('}')");
  }
  tokenizer->readNextToken();
  skipWhitespace();

  return true;
}

void LessParser::parseRulesetStatements (LessStylesheet &stylesheet,
                                         LessRuleset &ruleset) {
  Token token;
  TokenList value;
  UnprocessedStatement* statement;
  CssComment* comment;

  while (true) {
    if (tokenizer->getTokenType() == Token::COMMENT) {
      comment = ruleset.createComment();
      comment->setComment(tokenizer->getToken());
      tokenizer->readNextToken();
      skipWhitespace();
    } else if (tokenizer->getTokenType() == Token::ATKEYWORD) {
      token = tokenizer->getToken();
      tokenizer->readNextToken();
      skipWhitespace();

      if (parseVariable(value)) {
        ruleset.putVariable(token, value);
        value.clear();

      } else if (token == "@media") {
        parseMediaQueryRuleset(token, stylesheet, ruleset);

      } else {
        throw new ParseException(tokenizer->getToken(),
                                 "Variable declaration after keyword.");
      }

    } else if ((statement = parseRulesetStatement(ruleset)) != NULL) {
      // a selector followed by a ruleset is a nested rule
      if (tokenizer->getTokenType() == Token::BRACKET_OPEN) {
        parseRuleset(stylesheet, *statement->getTokens(), &ruleset);
        ruleset.deleteUnprocessedStatement(*statement);
      }

    } else
      break;
  }
}

void LessParser::parseMediaQueryRuleset(Token &mediatoken,
                                        LessStylesheet &stylesheet,
                                        LessRuleset &parent) {

  MediaQueryRuleset* query = parent.createMediaQuery();
  Selector selector;

  query->setReference(reference);

  selector.push_back(mediatoken);
  selector.push_back(Token::BUILTIN_SPACE);

  CssParser::skipWhitespace();

  while (parseAny(selector) ||
         tokenizer->getTokenType() == Token::ATKEYWORD) {
    if (tokenizer->getTokenType() == Token::ATKEYWORD) {
      selector.push_back(tokenizer->getToken());
      tokenizer->readNextToken();
      parseWhitespace(selector);
    }
  }

  query->setSelector(selector);

  if (tokenizer->getTokenType() != Token::BRACKET_OPEN) {
    throw new ParseException(tokenizer->getToken(),
                             "{");
  }
  tokenizer->readNextToken();
  skipWhitespace();

  parseRulesetStatements(stylesheet, *query);

  if (tokenizer->getTokenType() != Token::BRACKET_CLOSED) {
    throw new ParseException(tokenizer->getToken(),
                             "end of media query block ('}')");
  }
  tokenizer->readNextToken();
  skipWhitespace();
}

bool LessParser::parsePropertyVariable(Selector &selector) {
  Token variable = tokenizer->getToken();

  if (tokenizer->getTokenType() != Token::OTHER ||
      variable != "@")
    return false;

  if (tokenizer->readNextToken() != Token::BRACKET_OPEN)
    throw new ParseException(tokenizer->getToken(),
                             "Opening bracket following @");
  variable.append(tokenizer->getToken());

  if (tokenizer->readNextToken() != Token::IDENTIFIER)
    throw new ParseException(tokenizer->getToken(),
                             "Variable inside selector (e.g.: \
@{identifier})");

  variable.append(tokenizer->getToken());

  if (tokenizer->readNextToken() != Token::BRACKET_CLOSED)
    throw new ParseException(tokenizer->getToken(),
                               "Closing bracket after variable.");

  variable.append(tokenizer->getToken());
  tokenizer->readNextToken();

  selector.push_back(variable);
  parseWhitespace(selector);

  return true;
}

UnprocessedStatement* LessParser::parseRulesetStatement (LessRuleset &ruleset) {
  UnprocessedStatement* statement;
  Selector tokens;
  size_t property_i;

  while (parseProperty(tokens) || parsePropertyVariable(tokens)) {}

  property_i = tokens.size();

  parseWhitespace(tokens);
  parseSelector(tokens);
  tokens.trim();

  if (tokens.empty())
    return NULL;

  statement = ruleset.createUnprocessedStatement();

  statement->getTokens()->swap(tokens);
  statement->property_i = property_i;

  if (tokenizer->getTokenType() == Token::BRACKET_OPEN)
    return statement;

  parseValue(*statement->getTokens());

  if (tokenizer->getTokenType() == Token::DELIMITER) {
    tokenizer->readNextToken();
    skipWhitespace();
  }
  return statement;
}

bool LessParser::parseImportStatement(TokenList &statement, LessStylesheet &stylesheet) {
  unsigned int directive = 0;

  // parse directives and strip from statement (the statement becomes a valid
  // css import statement.)
  if (statement.size() >= 4 &&
      statement.front().type == Token::PAREN_OPEN) {
    statement.pop_front();
    statement.ltrim();

    directive = parseImportDirective(statement.front());
    statement.pop_front();
    statement.ltrim();

    while (statement.size() > 0 && statement.front() == ",") {
      statement.pop_front();
      statement.ltrim();

      directive |= parseImportDirective(statement.front());
      statement.pop_front();
      statement.ltrim();
    }

    if (statement.size() > 0 &&
        statement.front().type != Token::PAREN_CLOSED)
      throw new ParseException(statement, ")");
  }

  if (statement.size() > 0 &&
      (statement.front().type == Token::URL ||
       statement.front().type == Token::STRING)) {
    return importFile(statement.front(), stylesheet, directive);

  } else
    throw new ParseException(statement, "A string with the file path, "
                             "or an import directive.");
}

unsigned int LessParser::parseImportDirective(Token &t) {
  if (t.type != Token::IDENTIFIER)
    throw new ParseException(t, "an import directive.");
  if (t == "reference")
    return IMPORT_REFERENCE;
  else if (t == "inline")
    return IMPORT_INLINE;
  else if (t == "less")
    return IMPORT_LESS;
  else if (t == "css")
    return IMPORT_CSS;
  else if (t == "once")
    return IMPORT_ONCE;
  else if (t == "multiple")
    return IMPORT_MULTIPLE;
  else if (t == "optional")
    return IMPORT_OPTIONAL;
  else
    throw new ParseException(t, "valid import directive: reference, "
                             "inline, less, css, once, multiple or optional");
}

bool LessParser::importFile(Token uri,
                            LessStylesheet &stylesheet,
                            unsigned int directive) {
  size_t pathend;
  size_t pos;
  size_t extension_pos;
  std::string source;
  std::string relative_filename;
  std::list<const char*>::iterator i;
  char* relative_filename_cpy;
  std::string extension;

  if (uri.type == Token::URL) {
    uri = uri.getUrlString();

  } else if (uri.type == Token::STRING) {
    uri.removeQuotes();
  }

#ifdef WITH_LIBGLOG
  VLOG(2) << "Import filename: " << uri;
#endif

  // no remote includes
  if (uri.substr(0, 7) == "http://")
    return false;

  pathend = uri.rfind('?');
  if (pathend == std::string::npos)
    pathend = uri.size();

  extension_pos = uri.rfind('.', pathend);
  if (extension_pos == std::string::npos) {
    uri.insert(pathend, ".less");
    pathend += 5;
    extension = "less";
  } else
    extension = uri.substr(extension_pos + 1, pathend);

  // don't import css, unless specified with directive
  // don't import if css directive is given
  if ((extension == "css" &&
       !(directive & IMPORT_LESS)) ||

      (directive & IMPORT_CSS)) {
    return false;
  }

  // uri.source is the sourcefile that is currently parsed.
  source = uri.source;
  pos = source.find_last_of("/\\");

  // if the current stylesheet is outside of the current working
  //  directory then add the directory to the filename.
  if (pos != std::string::npos) {
    relative_filename.append(source.substr(0, pos + 1));
    relative_filename.append(uri);
  } else
    relative_filename = uri;

  if (!(directive & IMPORT_MULTIPLE)) {
    // check if the file has already been imported.
    for (i = sources.begin(); i != sources.end(); i++) {
      if (relative_filename == (*i))
        return true;
    }
  }

  ifstream in(relative_filename.c_str());
  if (in.fail() || in.bad()) {
    if (directive & IMPORT_OPTIONAL)
      return true;
    else {
      throw new ParseException(relative_filename, "existing file",
                               uri.line, uri.column, uri.source);
    }
  }

#ifdef WITH_LIBGLOG
  VLOG(1) << "Opening: " << relative_filename;
#endif

  relative_filename_cpy = new char[relative_filename.length() + 1];
  std::strcpy(relative_filename_cpy, relative_filename.c_str());

  sources.push_back(relative_filename_cpy);
  LessTokenizer tokenizer(in, relative_filename_cpy);
  LessParser parser(tokenizer, sources, (directive & IMPORT_REFERENCE));

#ifdef WITH_LIBGLOG
  VLOG(2) << "Parsing";
#endif

  parser.parseStylesheet(stylesheet);
  in.close();
  return true;
}

void LessParser::parseLessMediaQuery(Token &mediatoken,
                                     LessStylesheet &stylesheet) {
  LessMediaQuery* query = stylesheet.createLessMediaQuery();
  query->setReference(reference);

  query->getSelector()->push_back(mediatoken);
  query->getSelector()->push_back(Token::BUILTIN_SPACE);

  CssParser::skipWhitespace();

  while (parseAny(*query->getSelector()) ||
         tokenizer->getTokenType() == Token::ATKEYWORD) {
    if (tokenizer->getTokenType() == Token::ATKEYWORD) {
      query->getSelector()->push_back(tokenizer->getToken());
      tokenizer->readNextToken();
      parseWhitespace(*query->getSelector());
    }
  }

#ifdef WITH_LIBGLOG
  VLOG(2) << "Media query: " << query->getSelector()->toString();
#endif

  if (tokenizer->getTokenType() != Token::BRACKET_OPEN) {
    throw new ParseException(tokenizer->getToken(),
                             "{");
  }
  tokenizer->readNextToken();

  skipWhitespace();
  while (parseStatement(*query)) {
    skipWhitespace();
  }

  if (tokenizer->getTokenType() != Token::BRACKET_CLOSED) {
    throw new ParseException(tokenizer->getToken(),
                             "end of media query block ('}')");
  }
  tokenizer->readNextToken();
  skipWhitespace();
}
<commit_msg>Forgot to parse closing parenthesis in import directive.<commit_after>/*
 * Copyright 2012 Bram van der Kroef
 *
 * This file is part of LESS CSS Compiler.
 *
 * LESS CSS Compiler is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LESS CSS Compiler is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LESS CSS Compiler.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Bram van der Kroef <bram@vanderkroef.net>
 */

#include "LessParser.h"
#include <config.h>

#ifdef WITH_LIBGLOG
#include <glog/logging.h>
#endif

#include <libgen.h>

/**
 * Only allows LessStylesheets
 */
void LessParser::parseStylesheet(LessStylesheet &stylesheet) {
#ifdef WITH_LIBGLOG
  VLOG(1) << "Parser Start";
#endif

  CssParser::parseStylesheet(stylesheet);

#ifdef WITH_LIBGLOG
  VLOG(1) << "Parser End";
#endif
}

void LessParser::skipWhitespace () {
  while (tokenizer->getTokenType() == Token::WHITESPACE ||
         (tokenizer->getTokenType() == Token::COMMENT &&
          tokenizer->getToken().compare(0, 2, "//") == 0)) {
    tokenizer->readNextToken();
  }
}

bool LessParser::parseStatement(Stylesheet &stylesheet) {
  Selector selector;
  Mixin* mixin;
  CssComment* comment;
  LessStylesheet* ls = (LessStylesheet*)&stylesheet;

  if (tokenizer->getTokenType() == Token::COMMENT) {
    comment = ls->createComment();
    comment->setComment(tokenizer->getToken());
    tokenizer->readNextToken();
    skipWhitespace();
    return true;
  } else if (parseSelector(selector) && !selector.empty()) {
#ifdef WITH_LIBGLOG
    VLOG(2) << "Parse: Selector: " << selector.toString();
#endif

    if (parseRuleset(*ls, selector))
      return true;

    // Parameter mixin in the root. Inserts nested rules but no
    // declarations.
    mixin = ls->createMixin();
    mixin->setReference(reference);

    if (mixin->parse(selector)) {
      if (tokenizer->getTokenType() == Token::DELIMITER) {
        tokenizer->readNextToken();
        skipWhitespace();
      }
      return true;
    } else {
      ls->deleteMixin(*mixin);
      throw new ParseException(tokenizer->getToken(),
                               "a declaration block ('{...}') following selector");
    }

  } else {
    return parseAtRuleOrVariable(*ls);
  }
}

bool LessParser::parseAtRuleOrVariable (LessStylesheet &stylesheet) {
  Token token;
  TokenList value, rule;
  AtRule* atrule = NULL;

  if (tokenizer->getTokenType() != Token::ATKEYWORD)
    return false;

  token = tokenizer->getToken();
  tokenizer->readNextToken();
  CssParser::skipWhitespace();

#ifdef WITH_LIBGLOG
  VLOG(2) << "Parse: keyword: " << token;
#endif

  if (parseVariable(value)) {
#ifdef WITH_LIBGLOG
    VLOG(2) << "Parse: variable";
#endif
    stylesheet.putVariable(token, value);

  } else {
    if (token == "@media") {
      parseLessMediaQuery(token, stylesheet);
      return true;
    }

    while(parseAny(rule)) {};

    if (!parseBlock(rule)) {
      if (tokenizer->getTokenType() != Token::DELIMITER) {
        throw new ParseException(tokenizer->getToken(),
                                 "delimiter (';') at end of @-rule");
      }
      tokenizer->readNextToken();
      skipWhitespace();
    }
    // parse import
    if (token == "@import" && rule.size() > 0) {
      if (parseImportStatement(rule, stylesheet))
        return true;
    }

    atrule = stylesheet.createLessAtRule(token);
    atrule->setReference(reference);
    atrule->setRule(rule);
  }
  return true;
}

bool LessParser::parseVariable (TokenList &value) {
  if (tokenizer->getTokenType() != Token::COLON)
    return false;

  tokenizer->readNextToken();
  CssParser::skipWhitespace();

  if (parseValue(value) == false || value.size() == 0) {
    throw new ParseException(tokenizer->getToken(),
                             "value for variable");
  }
  if (tokenizer->getTokenType() != Token::DELIMITER) {
    throw new ParseException(tokenizer->getToken(),
                             "delimiter (';') at end of @-rule");
  }
  tokenizer->readNextToken();
  skipWhitespace();

  return true;
}

bool LessParser::parseSelector(Selector &selector) {
  if (!parseAny(selector))
    return false;

  while (parseAny(selector) || parseSelectorVariable(selector)) {};

  // delete trailing whitespace
  selector.rtrim();
  return true;
}

bool LessParser::parseSelectorVariable(Selector &selector) {
  Token* back;

  if (tokenizer->getTokenType() == Token::BRACKET_OPEN) {
    back = &selector.back();

    if (back->at(back->length() - 1) == '@') {
      back->append(tokenizer->getToken());

      if (tokenizer->readNextToken() != Token::IDENTIFIER)
        throw new ParseException(tokenizer->getToken(),
                                 "Variable inside selector (e.g.: \
@{identifier})");
      back->append(tokenizer->getToken());

      if (tokenizer->readNextToken() != Token::BRACKET_CLOSED)
        throw new ParseException(tokenizer->getToken(),
                                 "Closing bracket after variable.");

      back->append(tokenizer->getToken());
      tokenizer->readNextToken();

      parseWhitespace(selector);

      return true;
    }
  }
  return false;
}

bool LessParser::parseRuleset (LessStylesheet &stylesheet,
                               Selector &selector,
                               LessRuleset* parent) {
  LessRuleset* ruleset;

  if (tokenizer->getTokenType() != Token::BRACKET_OPEN)
    return false;

  tokenizer->readNextToken();
  skipWhitespace();

#ifdef WITH_LIBGLOG
  VLOG(2) << "Parse: Ruleset";
#endif

  // Create the ruleset and parse ruleset statements.
  if (parent == NULL)
    ruleset = stylesheet.createLessRuleset();
  else
    ruleset = parent->createNestedRule();
  ruleset->setReference(reference);
  ruleset->setSelector(selector);

  parseRulesetStatements(stylesheet, *ruleset);

  if (tokenizer->getTokenType() != Token::BRACKET_CLOSED) {
    throw new ParseException(tokenizer->getToken(),
                             "end of declaration block ('}')");
  }
  tokenizer->readNextToken();
  skipWhitespace();

  return true;
}

void LessParser::parseRulesetStatements (LessStylesheet &stylesheet,
                                         LessRuleset &ruleset) {
  Token token;
  TokenList value;
  UnprocessedStatement* statement;
  CssComment* comment;

  while (true) {
    if (tokenizer->getTokenType() == Token::COMMENT) {
      comment = ruleset.createComment();
      comment->setComment(tokenizer->getToken());
      tokenizer->readNextToken();
      skipWhitespace();
    } else if (tokenizer->getTokenType() == Token::ATKEYWORD) {
      token = tokenizer->getToken();
      tokenizer->readNextToken();
      skipWhitespace();

      if (parseVariable(value)) {
        ruleset.putVariable(token, value);
        value.clear();

      } else if (token == "@media") {
        parseMediaQueryRuleset(token, stylesheet, ruleset);

      } else {
        throw new ParseException(tokenizer->getToken(),
                                 "Variable declaration after keyword.");
      }

    } else if ((statement = parseRulesetStatement(ruleset)) != NULL) {
      // a selector followed by a ruleset is a nested rule
      if (tokenizer->getTokenType() == Token::BRACKET_OPEN) {
        parseRuleset(stylesheet, *statement->getTokens(), &ruleset);
        ruleset.deleteUnprocessedStatement(*statement);
      }

    } else
      break;
  }
}

void LessParser::parseMediaQueryRuleset(Token &mediatoken,
                                        LessStylesheet &stylesheet,
                                        LessRuleset &parent) {

  MediaQueryRuleset* query = parent.createMediaQuery();
  Selector selector;

  query->setReference(reference);

  selector.push_back(mediatoken);
  selector.push_back(Token::BUILTIN_SPACE);

  CssParser::skipWhitespace();

  while (parseAny(selector) ||
         tokenizer->getTokenType() == Token::ATKEYWORD) {
    if (tokenizer->getTokenType() == Token::ATKEYWORD) {
      selector.push_back(tokenizer->getToken());
      tokenizer->readNextToken();
      parseWhitespace(selector);
    }
  }

  query->setSelector(selector);

  if (tokenizer->getTokenType() != Token::BRACKET_OPEN) {
    throw new ParseException(tokenizer->getToken(),
                             "{");
  }
  tokenizer->readNextToken();
  skipWhitespace();

  parseRulesetStatements(stylesheet, *query);

  if (tokenizer->getTokenType() != Token::BRACKET_CLOSED) {
    throw new ParseException(tokenizer->getToken(),
                             "end of media query block ('}')");
  }
  tokenizer->readNextToken();
  skipWhitespace();
}

bool LessParser::parsePropertyVariable(Selector &selector) {
  Token variable = tokenizer->getToken();

  if (tokenizer->getTokenType() != Token::OTHER ||
      variable != "@")
    return false;

  if (tokenizer->readNextToken() != Token::BRACKET_OPEN)
    throw new ParseException(tokenizer->getToken(),
                             "Opening bracket following @");
  variable.append(tokenizer->getToken());

  if (tokenizer->readNextToken() != Token::IDENTIFIER)
    throw new ParseException(tokenizer->getToken(),
                             "Variable inside selector (e.g.: \
@{identifier})");

  variable.append(tokenizer->getToken());

  if (tokenizer->readNextToken() != Token::BRACKET_CLOSED)
    throw new ParseException(tokenizer->getToken(),
                               "Closing bracket after variable.");

  variable.append(tokenizer->getToken());
  tokenizer->readNextToken();

  selector.push_back(variable);
  parseWhitespace(selector);

  return true;
}

UnprocessedStatement* LessParser::parseRulesetStatement (LessRuleset &ruleset) {
  UnprocessedStatement* statement;
  Selector tokens;
  size_t property_i;

  while (parseProperty(tokens) || parsePropertyVariable(tokens)) {}

  property_i = tokens.size();

  parseWhitespace(tokens);
  parseSelector(tokens);
  tokens.trim();

  if (tokens.empty())
    return NULL;

  statement = ruleset.createUnprocessedStatement();

  statement->getTokens()->swap(tokens);
  statement->property_i = property_i;

  if (tokenizer->getTokenType() == Token::BRACKET_OPEN)
    return statement;

  parseValue(*statement->getTokens());

  if (tokenizer->getTokenType() == Token::DELIMITER) {
    tokenizer->readNextToken();
    skipWhitespace();
  }
  return statement;
}

bool LessParser::parseImportStatement(TokenList &statement, LessStylesheet &stylesheet) {
  unsigned int directive = 0;

  // parse directives and strip from statement (the statement becomes a valid
  // css import statement.)
  if (statement.size() >= 4 &&
      statement.front().type == Token::PAREN_OPEN) {
    statement.pop_front();
    statement.ltrim();

    directive = parseImportDirective(statement.front());
    statement.pop_front();
    statement.ltrim();

    while (statement.size() > 0 && statement.front() == ",") {
      statement.pop_front();
      statement.ltrim();

      directive |= parseImportDirective(statement.front());
      statement.pop_front();
      statement.ltrim();
    }

    if (statement.size() > 0 &&
        statement.front().type != Token::PAREN_CLOSED) {
      throw new ParseException(statement, ")");
    } else {
      statement.pop_front();
      statement.ltrim();
    }
  }

  if (statement.size() > 0 &&
      (statement.front().type == Token::URL ||
       statement.front().type == Token::STRING)) {
    return importFile(statement.front(), stylesheet, directive);

  } else
    throw new ParseException(statement, "A string with the file path, "
                             "or an import directive.");
}

unsigned int LessParser::parseImportDirective(Token &t) {
  if (t.type != Token::IDENTIFIER)
    throw new ParseException(t, "an import directive.");
  if (t == "reference")
    return IMPORT_REFERENCE;
  else if (t == "inline")
    return IMPORT_INLINE;
  else if (t == "less")
    return IMPORT_LESS;
  else if (t == "css")
    return IMPORT_CSS;
  else if (t == "once")
    return IMPORT_ONCE;
  else if (t == "multiple")
    return IMPORT_MULTIPLE;
  else if (t == "optional")
    return IMPORT_OPTIONAL;
  else
    throw new ParseException(t, "valid import directive: reference, "
                             "inline, less, css, once, multiple or optional");
}

bool LessParser::importFile(Token uri,
                            LessStylesheet &stylesheet,
                            unsigned int directive) {
  size_t pathend;
  size_t pos;
  size_t extension_pos;
  std::string source;
  std::string relative_filename;
  std::list<const char*>::iterator i;
  char* relative_filename_cpy;
  std::string extension;

  if (uri.type == Token::URL) {
    uri = uri.getUrlString();

  } else if (uri.type == Token::STRING) {
    uri.removeQuotes();
  }

#ifdef WITH_LIBGLOG
  VLOG(2) << "Import filename: " << uri;
#endif

  // no remote includes
  if (uri.substr(0, 7) == "http://")
    return false;

  pathend = uri.rfind('?');
  if (pathend == std::string::npos)
    pathend = uri.size();

  extension_pos = uri.rfind('.', pathend);
  if (extension_pos == std::string::npos) {
    uri.insert(pathend, ".less");
    pathend += 5;
    extension = "less";
  } else
    extension = uri.substr(extension_pos + 1, pathend);

  // don't import css, unless specified with directive
  // don't import if css directive is given
  if ((extension == "css" &&
       !(directive & IMPORT_LESS)) ||

      (directive & IMPORT_CSS)) {
    return false;
  }

  // uri.source is the sourcefile that is currently parsed.
  source = uri.source;
  pos = source.find_last_of("/\\");

  // if the current stylesheet is outside of the current working
  //  directory then add the directory to the filename.
  if (pos != std::string::npos) {
    relative_filename.append(source.substr(0, pos + 1));
    relative_filename.append(uri);
  } else
    relative_filename = uri;

  if (!(directive & IMPORT_MULTIPLE)) {
    // check if the file has already been imported.
    for (i = sources.begin(); i != sources.end(); i++) {
      if (relative_filename == (*i))
        return true;
    }
  }

  ifstream in(relative_filename.c_str());
  if (in.fail() || in.bad()) {
    if (directive & IMPORT_OPTIONAL)
      return true;
    else {
      throw new ParseException(relative_filename, "existing file",
                               uri.line, uri.column, uri.source);
    }
  }

#ifdef WITH_LIBGLOG
  VLOG(1) << "Opening: " << relative_filename;
#endif

  relative_filename_cpy = new char[relative_filename.length() + 1];
  std::strcpy(relative_filename_cpy, relative_filename.c_str());

  sources.push_back(relative_filename_cpy);
  LessTokenizer tokenizer(in, relative_filename_cpy);
  LessParser parser(tokenizer, sources, (directive & IMPORT_REFERENCE));

#ifdef WITH_LIBGLOG
  VLOG(2) << "Parsing";
#endif

  parser.parseStylesheet(stylesheet);
  in.close();
  return true;
}

void LessParser::parseLessMediaQuery(Token &mediatoken,
                                     LessStylesheet &stylesheet) {
  LessMediaQuery* query = stylesheet.createLessMediaQuery();
  query->setReference(reference);

  query->getSelector()->push_back(mediatoken);
  query->getSelector()->push_back(Token::BUILTIN_SPACE);

  CssParser::skipWhitespace();

  while (parseAny(*query->getSelector()) ||
         tokenizer->getTokenType() == Token::ATKEYWORD) {
    if (tokenizer->getTokenType() == Token::ATKEYWORD) {
      query->getSelector()->push_back(tokenizer->getToken());
      tokenizer->readNextToken();
      parseWhitespace(*query->getSelector());
    }
  }

#ifdef WITH_LIBGLOG
  VLOG(2) << "Media query: " << query->getSelector()->toString();
#endif

  if (tokenizer->getTokenType() != Token::BRACKET_OPEN) {
    throw new ParseException(tokenizer->getToken(),
                             "{");
  }
  tokenizer->readNextToken();

  skipWhitespace();
  while (parseStatement(*query)) {
    skipWhitespace();
  }

  if (tokenizer->getTokenType() != Token::BRACKET_CLOSED) {
    throw new ParseException(tokenizer->getToken(),
                             "end of media query block ('}')");
  }
  tokenizer->readNextToken();
  skipWhitespace();
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libvisio project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "VSDMetaData.h"
#include <cmath>
#include <unicode/ucnv.h>
#include <ctime>

libvisio::VSDMetaData::VSDMetaData()
  : m_idsAndOffsets(), m_typedPropertyValues(), m_metaData()
{
}

libvisio::VSDMetaData::~VSDMetaData()
{
}

bool libvisio::VSDMetaData::parse(librevenge::RVNGInputStream *input)
{
  if (!input)
    return false;

  readPropertySetStream(input);

  return true;
}

void libvisio::VSDMetaData::readPropertySetStream(librevenge::RVNGInputStream *input)
{
  // ByteOrder
  input->seek(2, librevenge::RVNG_SEEK_CUR);
  // Version
  input->seek(2, librevenge::RVNG_SEEK_CUR);
  // SystemIdentifier
  input->seek(4, librevenge::RVNG_SEEK_CUR);
  // CLSID
  input->seek(16, librevenge::RVNG_SEEK_CUR);
  // NumPropertySets
  input->seek(4, librevenge::RVNG_SEEK_CUR);
  // FMTID0
  input->seek(16, librevenge::RVNG_SEEK_CUR);
  uint32_t offset0 = readU32(input);
  readPropertySet(input, offset0);
}

void libvisio::VSDMetaData::readPropertySet(librevenge::RVNGInputStream *input, uint32_t offset)
{
  input->seek(offset, librevenge::RVNG_SEEK_SET);

  // Size
  input->seek(4, librevenge::RVNG_SEEK_CUR);
  uint32_t numProperties = readU32(input);
  for (uint32_t i = 0; i < numProperties; ++i)
    readPropertyIdentifierAndOffset(input);
  for (uint32_t i = 0; i < numProperties; ++i)
  {
    if (i >= m_idsAndOffsets.size())
      break;
    readTypedPropertyValue(input, i, offset + m_idsAndOffsets[i].second);
  }
}

#define CODEPAGE_PROPERTY_IDENTIFIER 0x00000001

uint32_t libvisio::VSDMetaData::getCodePage()
{
  for (size_t i = 0; i < m_idsAndOffsets.size(); ++i)
  {
    if (m_idsAndOffsets[i].first == CODEPAGE_PROPERTY_IDENTIFIER)
    {
      if (i >= m_typedPropertyValues.size())
        break;
      return m_typedPropertyValues[i];
    }
  }

  return 0;
}

void libvisio::VSDMetaData::readPropertyIdentifierAndOffset(librevenge::RVNGInputStream *input)
{
  uint32_t propertyIdentifier = readU32(input);
  uint32_t offset = readU32(input);
  m_idsAndOffsets.push_back(std::make_pair(propertyIdentifier, offset));
}

#define VT_I2 0x0002
#define VT_LPSTR 0x001E

#define PIDSI_TITLE 0x00000002
#define PIDSI_SUBJECT 0x00000003
#define PIDSI_AUTHOR 0x00000004
#define PIDSI_KEYWORDS 0x00000005
#define PIDSI_COMMENTS 0x00000006

void libvisio::VSDMetaData::readTypedPropertyValue(librevenge::RVNGInputStream *input, uint32_t index, uint32_t offset)
{
  input->seek(offset, librevenge::RVNG_SEEK_SET);
  uint16_t type = readU16(input);
  // Padding
  input->seek(2, librevenge::RVNG_SEEK_CUR);

  if (type == VT_I2)
  {
    uint16_t value = readU16(input);
    m_typedPropertyValues[index] = value;
  }
  else if (type == VT_LPSTR)
  {
    librevenge::RVNGString string = readCodePageString(input);
    if (!string.empty())
    {
      if (index >= m_idsAndOffsets.size())
        return;

      switch (m_idsAndOffsets[index].first)
      {
      case PIDSI_TITLE:
        m_metaData.insert("dc:title", string);
        break;
      case PIDSI_SUBJECT:
        m_metaData.insert("dc:subject", string);
        break;
      case PIDSI_AUTHOR:
        m_metaData.insert("meta:initial-creator", string);
        m_metaData.insert("dc:creator", string);
        break;
      case PIDSI_KEYWORDS:
        m_metaData.insert("meta:keyword", string);
        break;
      case PIDSI_COMMENTS:
        m_metaData.insert("dc:description", string);
        break;
      }
    }
  }
}

librevenge::RVNGString libvisio::VSDMetaData::readCodePageString(librevenge::RVNGInputStream *input)
{
  uint32_t size = readU32(input);

  std::vector<unsigned char> characters;
  for (uint32_t i = 0; i < size; ++i)
    characters.push_back(readU8(input));

  uint32_t codepage = getCodePage();
  librevenge::RVNGString string;

  if (codepage == 65001)
  {
    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130%28v=vs.85%29.aspx
    // says this is UTF-8.
    for (std::vector<unsigned char>::const_iterator i = characters.begin(); i != characters.end(); ++i)
      string.append((const char)*i);
  }
  else
  {
    UErrorCode status = U_ZERO_ERROR;
    UConverter *conv = 0;

    switch (codepage)
    {
    case 1252:
      // http://msdn.microsoft.com/en-us/goglobal/bb964654
      conv = ucnv_open("windows-1252", &status);
      break;
    }

    if (U_SUCCESS(status) && conv)
    {
      const char *src = (const char *)&characters[0];
      const char *srcLimit = (const char *)src + characters.size();
      while (src < srcLimit)
      {
        UChar32 ucs4Character = ucnv_getNextUChar(conv, &src, srcLimit, &status);
        if (U_SUCCESS(status) && U_IS_UNICODE_CHAR(ucs4Character))
          appendUCS4(string, ucs4Character);
      }
    }

    if (conv)
      ucnv_close(conv);
  }

  return string;
}

bool libvisio::VSDMetaData::parseTimes(librevenge::RVNGInputStream *input)
{
  // Parse the header
  // HeaderSignature: 8 bytes
  // HeaderCLSID: 16 bytes
  // MinorVersion: 2 bytes
  // MajorVersion: 2 bytes
  // ByteOrder: 2 bytes
  input->seek(30, librevenge::RVNG_SEEK_CUR);
  uint16_t sectorShift = readU16(input);
  // MiniSectorShift: 2 bytes
  // Reserved: 6 bytes
  // NumDirectorySectors: 4 bytes
  // NumFATSectors: 4 bytes
  input->seek(16, librevenge::RVNG_SEEK_CUR);
  uint32_t firstDirSectorLocation = readU32(input);

  // Seek to the Root Directory Entry
  size_t sectorSize = pow(2, sectorShift);
  input->seek((firstDirSectorLocation + 1) * sectorSize, librevenge::RVNG_SEEK_SET);
  // DirectoryEntryName: 64 bytes
  // DirectoryEntryNameLength: 2 bytes
  // ObjectType: 1 byte
  // ColorFlag: 1 byte
  // LeftSiblingID: 4 bytes
  // RightSiblingID: 4 bytes
  // ChildID: 4 bytes
  // CLSID: 16 bytes
  // StateBits: 4 bytes
  // CreationTime: 8 bytes
  input->seek(108, librevenge::RVNG_SEEK_CUR);
  uint64_t modifiedTime = readU64(input);

  // modifiedTime is number of 100ns since Jan 1 1601
  const uint64_t epoch = uint64_t(116444736UL) * 100;
  time_t sec = (modifiedTime / 10000000) - epoch;
  const struct tm *time = localtime(&sec);
  if (time)
  {
    static const int MAX_BUFFER = 1024;
    char buffer[MAX_BUFFER];
    strftime(&buffer[0], MAX_BUFFER-1, "%Y-%m-%dT%H:%M:%SZ", time);
    librevenge::RVNGString result;
    result.append(buffer);
    // Visio UI uses modifiedTime for both purposes.
    m_metaData.insert("meta:creation-date", result);
    m_metaData.insert("dc:date", result);
    return true;
  }
  return false;
}

const librevenge::RVNGPropertyList &libvisio::VSDMetaData::getMetaData()
{
  return m_metaData;
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>use std::pow in order to avoid compile time errors like: error: call of overloaded 'pow(int, uint16_t&)' is ambiguous<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libvisio project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "VSDMetaData.h"
#include <cmath>
#include <unicode/ucnv.h>
#include <ctime>

libvisio::VSDMetaData::VSDMetaData()
  : m_idsAndOffsets(), m_typedPropertyValues(), m_metaData()
{
}

libvisio::VSDMetaData::~VSDMetaData()
{
}

bool libvisio::VSDMetaData::parse(librevenge::RVNGInputStream *input)
{
  if (!input)
    return false;

  readPropertySetStream(input);

  return true;
}

void libvisio::VSDMetaData::readPropertySetStream(librevenge::RVNGInputStream *input)
{
  // ByteOrder
  input->seek(2, librevenge::RVNG_SEEK_CUR);
  // Version
  input->seek(2, librevenge::RVNG_SEEK_CUR);
  // SystemIdentifier
  input->seek(4, librevenge::RVNG_SEEK_CUR);
  // CLSID
  input->seek(16, librevenge::RVNG_SEEK_CUR);
  // NumPropertySets
  input->seek(4, librevenge::RVNG_SEEK_CUR);
  // FMTID0
  input->seek(16, librevenge::RVNG_SEEK_CUR);
  uint32_t offset0 = readU32(input);
  readPropertySet(input, offset0);
}

void libvisio::VSDMetaData::readPropertySet(librevenge::RVNGInputStream *input, uint32_t offset)
{
  input->seek(offset, librevenge::RVNG_SEEK_SET);

  // Size
  input->seek(4, librevenge::RVNG_SEEK_CUR);
  uint32_t numProperties = readU32(input);
  for (uint32_t i = 0; i < numProperties; ++i)
    readPropertyIdentifierAndOffset(input);
  for (uint32_t i = 0; i < numProperties; ++i)
  {
    if (i >= m_idsAndOffsets.size())
      break;
    readTypedPropertyValue(input, i, offset + m_idsAndOffsets[i].second);
  }
}

#define CODEPAGE_PROPERTY_IDENTIFIER 0x00000001

uint32_t libvisio::VSDMetaData::getCodePage()
{
  for (size_t i = 0; i < m_idsAndOffsets.size(); ++i)
  {
    if (m_idsAndOffsets[i].first == CODEPAGE_PROPERTY_IDENTIFIER)
    {
      if (i >= m_typedPropertyValues.size())
        break;
      return m_typedPropertyValues[i];
    }
  }

  return 0;
}

void libvisio::VSDMetaData::readPropertyIdentifierAndOffset(librevenge::RVNGInputStream *input)
{
  uint32_t propertyIdentifier = readU32(input);
  uint32_t offset = readU32(input);
  m_idsAndOffsets.push_back(std::make_pair(propertyIdentifier, offset));
}

#define VT_I2 0x0002
#define VT_LPSTR 0x001E

#define PIDSI_TITLE 0x00000002
#define PIDSI_SUBJECT 0x00000003
#define PIDSI_AUTHOR 0x00000004
#define PIDSI_KEYWORDS 0x00000005
#define PIDSI_COMMENTS 0x00000006

void libvisio::VSDMetaData::readTypedPropertyValue(librevenge::RVNGInputStream *input, uint32_t index, uint32_t offset)
{
  input->seek(offset, librevenge::RVNG_SEEK_SET);
  uint16_t type = readU16(input);
  // Padding
  input->seek(2, librevenge::RVNG_SEEK_CUR);

  if (type == VT_I2)
  {
    uint16_t value = readU16(input);
    m_typedPropertyValues[index] = value;
  }
  else if (type == VT_LPSTR)
  {
    librevenge::RVNGString string = readCodePageString(input);
    if (!string.empty())
    {
      if (index >= m_idsAndOffsets.size())
        return;

      switch (m_idsAndOffsets[index].first)
      {
      case PIDSI_TITLE:
        m_metaData.insert("dc:title", string);
        break;
      case PIDSI_SUBJECT:
        m_metaData.insert("dc:subject", string);
        break;
      case PIDSI_AUTHOR:
        m_metaData.insert("meta:initial-creator", string);
        m_metaData.insert("dc:creator", string);
        break;
      case PIDSI_KEYWORDS:
        m_metaData.insert("meta:keyword", string);
        break;
      case PIDSI_COMMENTS:
        m_metaData.insert("dc:description", string);
        break;
      }
    }
  }
}

librevenge::RVNGString libvisio::VSDMetaData::readCodePageString(librevenge::RVNGInputStream *input)
{
  uint32_t size = readU32(input);

  std::vector<unsigned char> characters;
  for (uint32_t i = 0; i < size; ++i)
    characters.push_back(readU8(input));

  uint32_t codepage = getCodePage();
  librevenge::RVNGString string;

  if (codepage == 65001)
  {
    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130%28v=vs.85%29.aspx
    // says this is UTF-8.
    for (std::vector<unsigned char>::const_iterator i = characters.begin(); i != characters.end(); ++i)
      string.append((const char)*i);
  }
  else
  {
    UErrorCode status = U_ZERO_ERROR;
    UConverter *conv = 0;

    switch (codepage)
    {
    case 1252:
      // http://msdn.microsoft.com/en-us/goglobal/bb964654
      conv = ucnv_open("windows-1252", &status);
      break;
    }

    if (U_SUCCESS(status) && conv)
    {
      const char *src = (const char *)&characters[0];
      const char *srcLimit = (const char *)src + characters.size();
      while (src < srcLimit)
      {
        UChar32 ucs4Character = ucnv_getNextUChar(conv, &src, srcLimit, &status);
        if (U_SUCCESS(status) && U_IS_UNICODE_CHAR(ucs4Character))
          appendUCS4(string, ucs4Character);
      }
    }

    if (conv)
      ucnv_close(conv);
  }

  return string;
}

bool libvisio::VSDMetaData::parseTimes(librevenge::RVNGInputStream *input)
{
  // Parse the header
  // HeaderSignature: 8 bytes
  // HeaderCLSID: 16 bytes
  // MinorVersion: 2 bytes
  // MajorVersion: 2 bytes
  // ByteOrder: 2 bytes
  input->seek(30, librevenge::RVNG_SEEK_CUR);
  uint16_t sectorShift = readU16(input);
  // MiniSectorShift: 2 bytes
  // Reserved: 6 bytes
  // NumDirectorySectors: 4 bytes
  // NumFATSectors: 4 bytes
  input->seek(16, librevenge::RVNG_SEEK_CUR);
  uint32_t firstDirSectorLocation = readU32(input);

  // Seek to the Root Directory Entry
  size_t sectorSize = std::pow(2, sectorShift);
  input->seek((firstDirSectorLocation + 1) * sectorSize, librevenge::RVNG_SEEK_SET);
  // DirectoryEntryName: 64 bytes
  // DirectoryEntryNameLength: 2 bytes
  // ObjectType: 1 byte
  // ColorFlag: 1 byte
  // LeftSiblingID: 4 bytes
  // RightSiblingID: 4 bytes
  // ChildID: 4 bytes
  // CLSID: 16 bytes
  // StateBits: 4 bytes
  // CreationTime: 8 bytes
  input->seek(108, librevenge::RVNG_SEEK_CUR);
  uint64_t modifiedTime = readU64(input);

  // modifiedTime is number of 100ns since Jan 1 1601
  const uint64_t epoch = uint64_t(116444736UL) * 100;
  time_t sec = (modifiedTime / 10000000) - epoch;
  const struct tm *time = localtime(&sec);
  if (time)
  {
    static const int MAX_BUFFER = 1024;
    char buffer[MAX_BUFFER];
    strftime(&buffer[0], MAX_BUFFER-1, "%Y-%m-%dT%H:%M:%SZ", time);
    librevenge::RVNGString result;
    result.append(buffer);
    // Visio UI uses modifiedTime for both purposes.
    m_metaData.insert("meta:creation-date", result);
    m_metaData.insert("dc:date", result);
    return true;
  }
  return false;
}

const librevenge::RVNGPropertyList &libvisio::VSDMetaData::getMetaData()
{
  return m_metaData;
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<|endoftext|>


<commit_before>#include "graph3d.h"
#include <math.h>
#include <memory.h>
#include <stdlib.h>
#include "lib/gfx/bitmap.h"

struct Vector2
{
    float x, y;
};

struct Vector3
{
    float x, y, z;
};

struct Point
{
    Vector3 src;        // Original co-ords passed to AddPoint
    Vector3 dst;        // Co-ords after transforms
    RGBAColour col;
};

#define NUM_DEPTH_BINS 16
struct Graph3d
{
    Point *points;      // First 8 points hold the corners of the cube
    int numPoints;
    int maxPoints;

    float minZ;
    float maxZ;
    int *depthBins[NUM_DEPTH_BINS];  // Indices into points, grouped by depth
    int *depthBinsBuf;

    Vector3 maxPoint;   // Holds the highest x, y and z values seen in all the points
    Vector3 minPoint;
};

DLL_API Graph3d *CreateGraph3d()
{
    Graph3d *g = new Graph3d;
    memset(g, 0, sizeof(Graph3d));

    g->points = new Point [16];
    g->numPoints = 0;
    g->maxPoints = 16;

    g->depthBinsBuf = new int [16];

    return g;
}

DLL_API void Graph3dAddPoint(Graph3d *g, float x, float y, float z, RGBAColour col)
{
    if (g->numPoints == g->maxPoints)
    {
        Point *newPoints = new Point [g->maxPoints * 2];
        memcpy(newPoints, g->points, sizeof(Point) * g->maxPoints);
        g->maxPoints *= 2;
        delete [] g->points;
        g->points = newPoints;

        delete [] g->depthBinsBuf;
        g->depthBinsBuf = new int [g->maxPoints];
    }

    Point *p = &g->points[g->numPoints];
    p->src.x = x;
    p->src.y = y;
    p->src.z = z;
    p->col = col;
    g->numPoints++;

    g->maxPoint.x = __max(x, g->maxPoint.x);
    g->maxPoint.y = __max(y, g->maxPoint.y);
    g->maxPoint.z = __max(z, g->maxPoint.z);

    g->minPoint.x = __min(x, g->minPoint.x);
    g->minPoint.y = __min(y, g->minPoint.y);
    g->minPoint.z = __min(z, g->minPoint.z);
}

static void Rotate(Graph3d *g, float rotX, float rotZ)
{
    // Form bounding box
    g->points[0].src.x = g->minPoint.x;
    g->points[1].src.x = g->maxPoint.x;
    g->points[2].src.x = g->minPoint.x;
    g->points[3].src.x = g->maxPoint.x;
    g->points[4].src.x = g->minPoint.x;
    g->points[5].src.x = g->maxPoint.x;
    g->points[6].src.x = g->minPoint.x;
    g->points[7].src.x = g->maxPoint.x;

    g->points[0].src.y = g->minPoint.y;
    g->points[1].src.y = g->minPoint.y;
    g->points[2].src.y = g->maxPoint.y;
    g->points[3].src.y = g->maxPoint.y;
    g->points[4].src.y = g->minPoint.y;
    g->points[5].src.y = g->minPoint.y;
    g->points[6].src.y = g->maxPoint.y;
    g->points[7].src.y = g->maxPoint.y;

    g->points[0].src.z = g->minPoint.z;
    g->points[1].src.z = g->minPoint.z;
    g->points[2].src.z = g->minPoint.z;
    g->points[3].src.z = g->minPoint.z;
    g->points[4].src.z = g->maxPoint.z;
    g->points[5].src.z = g->maxPoint.z;
    g->points[6].src.z = g->maxPoint.z;
    g->points[7].src.z = g->maxPoint.z;

    float cx = cosf(rotX);
    float sx = sinf(rotX);
    float cz = cosf(rotZ);
    float sz = sinf(rotZ);

    // Transform points of data set
    for (int i = 0; i < g->numPoints; i++)
    {
        Vector3 *p = &g->points[i].src;
        Vector3 *q = &g->points[i].dst;

        // Rotate around z axis
        q->x = p->x * cz + p->z * sz;
        q->z = p->x * sz - p->z * cz;

        // Rotate around x axis
        q->y = p->y * cx + q->z * sx;
        q->z = q->z * cx - p->y * sx;
    }
}

static void DepthSort(Graph3d *graph)
{
    // Find the nearest and furthest point
    for (int i = 8; i < graph->numPoints; i++)
    {
        graph->minZ = __min(graph->minZ, graph->points[i].dst.z);
        graph->maxZ = __max(graph->maxZ, graph->points[i].dst.z);
    }

    float depthFactor = 15.0f / (graph->maxZ - graph->minZ);

    // Count the number of points in each depth bin
    int binCounts[NUM_DEPTH_BINS] = { 0 };      // Number of points in each bin
    for (int i = 8; i < graph->numPoints; i++)
    {
        int binIdx = NUM_DEPTH_BINS - int((graph->points[i].dst.z - graph->minZ) * depthFactor) - 1;
        binCounts[binIdx]++;
    }

    // Setup the depth bins to point to the correct amount of space in depthBinBuf
    int pointCount = 8;
    for (int i = 0; i < NUM_DEPTH_BINS; i++)
    {
        graph->depthBins[i] = &graph->depthBinsBuf[pointCount];
        pointCount += binCounts[i];
    }

    // Put the points in the appropriate bin
    memset(binCounts, 0, sizeof(binCounts));
    for (int i = 8; i < graph->numPoints; i++)
    {
        int binIdx = NUM_DEPTH_BINS - int((graph->points[i].dst.z - graph->minZ) * depthFactor) - 1;
        graph->depthBins[binIdx][binCounts[binIdx]] = i;
        binCounts[binIdx]++;
    }
}

static inline Vector2 ProjectPoint(Vector3 a, float cx, float cy, float dist, float zoom)
{
    Vector2 b;
    float z = a.z + dist;
    b.x = (a.x / z) * zoom + cx;
    b.y = (a.y / z) * zoom + cy;
    return b;
}

DLL_API void Graph3dRender(Graph3d *graph, BitmapRGBA *bmp, float cx, float cy,
                           float dist, float zoom, RGBAColour col,
                           float rotX, float rotZ)
{
    Rotate(graph, rotX, rotZ);
    DepthSort(graph);

    // Draw the points
    for (int i = 8; i < graph->numPoints; i++)
    {
        int idx = graph->depthBinsBuf[i];
        Vector2 p = ProjectPoint(graph->points[idx].dst, cx, cy, dist, zoom);
        PutPixelClipped(bmp, p.x, p.y, graph->points[idx].col);
        i++;
        idx = graph->depthBinsBuf[i];
        p = ProjectPoint(graph->points[idx].dst, cx, cy, dist, zoom);
        PutPixelClipped(bmp, p.x, p.y, graph->points[idx].col);
    }

    int boundingLines[] = {0,1, 1,3, 3,2, 2,0,
                           4,5, 5,7, 7,6, 6,4,
                           0,4, 1,5, 2,6, 3,7};

    // Draw the bounding cube
    for (int i = 0; i < 12; i++)
    {
        int idx1 = boundingLines[i*2];
        int idx2 = boundingLines[i*2+1];
        Vector2 a = ProjectPoint(graph->points[idx1].dst, cx, cy, dist, zoom);
        Vector2 b = ProjectPoint(graph->points[idx2].dst, cx, cy, dist, zoom);
        DrawLine(bmp, a.x, a.y, b.x, b.y, col);
    }
}
<commit_msg>Made Graph3d render twice as fast by replacing array of sorted indices with a sorted array of points. It's doing more work but is massively more cache efficient.<commit_after>#include "graph3d.h"
#include <math.h>
#include <memory.h>
#include <stdlib.h>
#include "lib/gfx/bitmap.h"

struct Vector2
{
    float x, y;
};

struct Vector3
{
    float x, y, z;
};

struct Point
{
    Vector3 src;        // Original co-ords passed to AddPoint
    Vector3 dst;        // Co-ords after transforms
    RGBAColour col;
};

struct SortedPoint
{
    Vector3 pos;
    RGBAColour col;
};

#define NUM_DEPTH_BINS 64
struct Graph3d
{
    Point *points;      // First 8 points hold the corners of the cube
    int numPoints;
    int maxPoints;

    float minZ;
    float maxZ;
    SortedPoint *sortedPoints;  // Only approximately sorted - good enough, fast and simple

    Vector3 maxPoint;   // Holds the highest x, y and z values seen in all the points
    Vector3 minPoint;
};

DLL_API Graph3d *CreateGraph3d()
{
    Graph3d *g = new Graph3d;
    memset(g, 0, sizeof(Graph3d));

    g->points = new Point [16];
    g->numPoints = 0;
    g->maxPoints = 16;

    g->sortedPoints = new SortedPoint [16];

    return g;
}

DLL_API void Graph3dAddPoint(Graph3d *g, float x, float y, float z, RGBAColour col)
{
    if (g->numPoints == g->maxPoints)
    {
        Point *newPoints = new Point [g->maxPoints * 2];
        memcpy(newPoints, g->points, sizeof(Point) * g->maxPoints);
        g->maxPoints *= 2;
        delete [] g->points;
        g->points = newPoints;

        delete [] g->sortedPoints;
        g->sortedPoints = new SortedPoint [g->maxPoints];
    }

    Point *p = &g->points[g->numPoints];
    p->src.x = x;
    p->src.y = y;
    p->src.z = z;
    p->col = col;
    g->numPoints++;

    g->maxPoint.x = __max(x, g->maxPoint.x);
    g->maxPoint.y = __max(y, g->maxPoint.y);
    g->maxPoint.z = __max(z, g->maxPoint.z);

    g->minPoint.x = __min(x, g->minPoint.x);
    g->minPoint.y = __min(y, g->minPoint.y);
    g->minPoint.z = __min(z, g->minPoint.z);
}

static void Rotate(Graph3d *g, float rotX, float rotZ)
{
    // Form bounding box
    for (int i = 0; i < 8; i++)
    {
        g->points[i].src.x = g->minPoint.x;
        g->points[i].src.y = g->minPoint.y;
        g->points[i].src.z = g->minPoint.z;

        if (i & 1)
            g->points[i].src.x = g->maxPoint.x;

        if (i & 2)
            g->points[i].src.y = g->maxPoint.y;

        if (i & 4)
            g->points[i].src.z = g->maxPoint.z;
    }

    float cx = cosf(rotX);
    float sx = sinf(rotX);
    float cz = cosf(rotZ);
    float sz = sinf(rotZ);

    // Transform points of data set
    for (int i = 0; i < g->numPoints; i++)
    {
        Vector3 *p = &g->points[i].src;
        Vector3 *q = &g->points[i].dst;

        // Rotate around z axis
        q->x = p->x * cz + p->z * sz;
        q->z = p->x * sz - p->z * cz;

        // Rotate around x axis
        q->y = p->y * cx + q->z * sx;
        q->z = q->z * cx - p->y * sx;
    }
}

static void DepthSort(Graph3d *graph)
{
    // Find the nearest and furthest point
    for (int i = 8; i < graph->numPoints; i++)
    {
        graph->minZ = __min(graph->minZ, graph->points[i].dst.z);
        graph->maxZ = __max(graph->maxZ, graph->points[i].dst.z);
    }

    float depthFactor = 15.0f / (graph->maxZ - graph->minZ);

    // Count the number of points in each depth bin
    int binCounts[NUM_DEPTH_BINS] = { 0 };      // Number of points in each bin
    for (int i = 8; i < graph->numPoints; i++)
    {
        int binIdx = NUM_DEPTH_BINS - int((graph->points[i].dst.z - graph->minZ) * depthFactor) - 1;
        binCounts[binIdx]++;
    }

    // Setup the depth bins to point to the correct amount of space in depthBinBuf
    int pointCount = 8;
    SortedPoint *depthBins[NUM_DEPTH_BINS];  // Indices into points, grouped by depth
    for (int i = 0; i < NUM_DEPTH_BINS; i++)
    {
        depthBins[i] = &graph->sortedPoints[pointCount];
        pointCount += binCounts[i];
    }

    // Put the points in the appropriate bin
    memset(binCounts, 0, sizeof(binCounts));
    for (int i = 8; i < graph->numPoints; i++)
    {
        // Find which bin this point belongs in
        int binIdx = NUM_DEPTH_BINS - int((graph->points[i].dst.z - graph->minZ) * depthFactor) - 1;

        // Copy the view space coords from the unsorted array of points into the
        // pseudo-sorted array.
        SortedPoint *thisBin = depthBins[binIdx];
        int idxIntoBin = binCounts[binIdx];
        memcpy(&thisBin[idxIntoBin].pos, &graph->points[i].dst, sizeof(Vector3));
        thisBin[idxIntoBin].col = graph->points[i].col;

        binCounts[binIdx]++;
    }
}

static inline Vector2 ProjectPoint(Vector3 a, float cx, float cy, float dist, float zoom)
{
    Vector2 b;
    float z = a.z + dist;
    b.x = (a.x / z) * zoom + cx;
    b.y = (a.y / z) * zoom + cy;
    return b;
}

DLL_API void Graph3dRender(Graph3d *graph, BitmapRGBA *bmp, float cx, float cy,
                           float dist, float zoom, RGBAColour col,
                           float rotX, float rotZ)
{
    Rotate(graph, rotX, rotZ);
    DepthSort(graph);

    // Draw the points
    for (int i = 8; i < graph->numPoints; i++)
    {
        Vector2 p = ProjectPoint(graph->sortedPoints[i].pos, cx, cy, dist, zoom);
        PutPixelClipped(bmp, p.x, p.y, graph->sortedPoints[i].col);
    }

    int boundingLines[] = {0,1, 1,3, 3,2, 2,0,
                           4,5, 5,7, 7,6, 6,4,
                           0,4, 1,5, 2,6, 3,7};

    // Draw the bounding cube
    for (int i = 0; i < 12; i++)
    {
        int idx1 = boundingLines[i*2];
        int idx2 = boundingLines[i*2+1];
        Vector2 a = ProjectPoint(graph->points[idx1].dst, cx, cy, dist, zoom);
        Vector2 b = ProjectPoint(graph->points[idx2].dst, cx, cy, dist, zoom);
        DrawLine(bmp, a.x, a.y, b.x, b.y, col);
    }
}
<|endoftext|>


<commit_before>// -*-Mode: C++;-*-
// $Id$

// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002-2007, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************
//
// File:
//   $Source$
//
// Purpose:
//   [The purpose of this file]
//
// Description:
//   [The set of functions, macros, etc. defined in the file]
//
//***************************************************************************

//************************* System Include Files ****************************

#include <iostream>
using std::ostream;

//*************************** User Include Files ****************************

#include <include/general.h>
#include <include/gnu_bfd.h>  // for bfd_getb32, bfd_getl32
#include <include/gnu_dis-asm.h>

#include "MipsISA.hpp"
#include "instructionSets/mips.h"

#include <lib/support/diagnostics.h>

//*************************** Forward Declarations ***************************

#if defined(HOST_PLATFORM_MIPS64LE_LINUX)
# define BFD_GETX32 bfd_getl32
# define BFD_PRINT_INSN_MIPS print_insn_little_mips
#else /* PLATFORM_MIPS_IRIX64 */
# define BFD_GETX32 bfd_getb32
# define BFD_PRINT_INSN_MIPS print_insn_big_mips
#endif

//****************************************************************************

static VMA
GNUvma2vma(bfd_vma di_vma, MachInsn* insn_addr, VMA insn_vma)
{
  // N.B.: The GNU decoders assume that the address of 'insn_addr' is
  // the actual the VMA in order to calculate VMA-relative targets.
  VMA x = (di_vma - PTR_TO_BFDVMA(insn_addr)) + insn_vma;
  return x;
}

static void
GNUbu_print_addr(bfd_vma di_vma, struct disassemble_info* di)
{
  GNUbu_disdata* data = (GNUbu_disdata*)di->application_data;

  VMA x = GNUvma2vma(di_vma, data->insn_addr, data->insn_vma);
  ostream* os = (ostream*)di->stream;
  *os << std::showbase << std::hex << x << std::dec;
}

//****************************************************************************
// MipsISA
//****************************************************************************

// See 'ISA.h' for comments on the interface

MipsISA::MipsISA()
  : m_di(NULL), m_di_dis(NULL)
{
  // See 'dis-asm.h'
  m_di = new disassemble_info;
  init_disassemble_info(m_di, stdout, GNUbu_fprintf_stub);
  m_di->arch = bfd_arch_mips;        // bfd_get_arch(abfd)
  m_di->mach = bfd_mach_mipsisa64r2; // bfd_get_mach(abfd)
#if defined(HOST_PLATFORM_MIPS64LE_LINUX)
  m_di->endian = BFD_ENDIAN_LITTLE;
#else
  m_di->endian = BFD_ENDIAN_BIG;
#endif
  m_di->read_memory_func = GNUbu_read_memory; // vs. 'buffer_read_memory'
  m_di->print_address_func = GNUbu_print_addr_stub; // vs. 'generic_print_addr'

  m_di_dis = new disassemble_info;
  init_disassemble_info(m_di_dis, stdout, GNUbu_fprintf);
  m_di_dis->application_data = (void*)&m_dis_data;
  m_di_dis->arch = m_di->arch;
  m_di_dis->mach = m_di->mach;
  m_di_dis->endian = m_di->endian;
  m_di_dis->read_memory_func = GNUbu_read_memory;
  m_di_dis->print_address_func = GNUbu_print_addr;
}

MipsISA::~MipsISA()
{
  delete m_di;
  delete m_di_dis;
}

ISA::InsnDesc
MipsISA::GetInsnDesc(MachInsn* mi, ushort opIndex, ushort sz)
{
  // We know that instruction sizes are guaranteed to be 4 bytes, but
  // the host may have a different byte order than the executable.
  uint32_t insn = (uint32_t)BFD_GETX32((const unsigned char*)mi);

  switch (insn & OP_MASK)
    {
    case OPSpecial:
      switch (insn & OPSpecial_MASK)
	{
	case JR:                        // Instructions from Table A-13
	  // JR $31 returns from a JAL call instruction.
	  if (REG_S(insn) == REG_RA) {
	    return InsnDesc(InsnDesc::SUBR_RET);
	  }
	  else {
	    return InsnDesc(InsnDesc::BR_UN_COND_IND);
	  }
	case JALR:
	  return InsnDesc(InsnDesc::SUBR_IND);

	case SYSCALL:                   // Instructions from Table A-16,
	case BREAK:                     //   Table A-17
	case TGE:   // Trap-on-Condition...
	case TGEU:
	case TLT:
	case TLTU:
	case TEQ:
	case TNE:
	  return InsnDesc(InsnDesc::SYS_CALL);

	case SYNC:
	  return InsnDesc(InsnDesc::OTHER);
	}
      break;
    case OPRegImm:
      switch (insn & OPRegImm_MASK)
	{
	case BLTZ:                      // Instructions from Table A-15
	case BGEZ:
	case BLTZL:
	case BGEZL:
	  return InsnDesc(InsnDesc::INT_BR_COND_REL);

	case BLTZAL:  // Link
	case BGEZAL:  // Link
	case BLTZALL: // Link
	case BGEZALL: // Link
	  return InsnDesc(InsnDesc::SUBR_REL);

	case TGEI:                      // Instructions from Table A-18
	case TGEIU: // Trap-on-Condition...
	case TLTI:
	case TLTIU:
	case TEQI:
	case TNEI:
	  return InsnDesc(InsnDesc::OTHER);
	}
      break;
    case OPCop1x:
      switch (insn & OPCop1x_MASK)
	{
	case LWXC1: // Word	        // Instructions from Table A-7
	  return InsnDesc(InsnDesc::MEM_LOAD);
	case LDXC1: // Doubleword
	  return InsnDesc(InsnDesc::MEM_LOAD);
	case SWXC1: // Word
	  return InsnDesc(InsnDesc::MEM_STORE);
	case SDXC1: // Doubleword
	  return InsnDesc(InsnDesc::MEM_STORE);
	}
      break;

    // Normal instruction class
    case LB:   // Byte                  // Instructions from Table A-3
    case LBU:  // Byte Unsigned         //  Table A-4, Table A-5, Table A-6
    case LH:   // Halfword
    case LHU:  // Halfword Unsigned
    case LW:   // Word
    case LWU:  // Word Unsigned
    case LWL:  // Word Left
    case LWR:  // Word Right
    case LL:   // Linked Word
    case LWC1: // Word
    case LWC2: // Word
      return InsnDesc(InsnDesc::MEM_LOAD);

    case LD:   // Doubleword
    case LDL:  // Doubleword Left
    case LDR:  // Doubleword Right
    case LLD:  // Linked Doubleword
    case LDC1: // Doubleword
    case LDC2: // Doubleword
      return InsnDesc(InsnDesc::MEM_LOAD); // Doubleword

    case SB:   // Byte
    case SH:   // Halfword
    case SW:   // Word
    case SWL:  // Word Left
    case SWR:  // Word Right
    case SC:   // Conditional Word
    case SWC1: // Word
    case SWC2: // Word
      return InsnDesc(InsnDesc::MEM_STORE);

    case SD:   // Doubleword
    case SDL:  // Doubleword Left
    case SDR:  // Doubleword Right
    case SCD:  // Conditional Doubleword
    case SDC1: // Doubleword
    case SDC2: // Doubleword
      return InsnDesc(InsnDesc::MEM_STORE); // Doubleword

                                        // Instructions from Table A-12
      // N.B.: These instructions are PC-region but we will treat them
      // as PC-relative
    case J:
      return InsnDesc(InsnDesc::BR_UN_COND_REL);
    case JAL:
      return InsnDesc(InsnDesc::SUBR_REL);

    case BEQ:                           // Instructions from Table A-14
      // If operands are the same then then there is no fall-thru branch.
      // Test for general case.
      if (REG_S(insn) == REG_T(insn))
	return InsnDesc(InsnDesc::BR_UN_COND_REL);
      else
	return InsnDesc(InsnDesc::INT_BR_COND_REL);
    case BNE:
    case BLEZ:
    case BGTZ:
    case BEQL:
    case BNEL:
    case BLEZL:
    case BGTZL:
      return InsnDesc(InsnDesc::INT_BR_COND_REL);

    default:
      break;
    }

  return InsnDesc(InsnDesc::OTHER);
}

VMA
MipsISA::GetInsnTargetVMA(MachInsn* mi, VMA pc, ushort opIndex, ushort sz)
{
  // We know that instruction sizes are guaranteed to be 4 bytes, but
  // the host may have a different byte order than the executable.
  uint32_t insn = (uint32_t)BFD_GETX32((const unsigned char*)mi);

  intptr_t offset;
  switch (insn & OP_MASK)
    {
    case OPSpecial:
      switch (insn & OPSpecial_MASK)
	{
	case JR:                        // Instructions from Table A-13
	case JALR:
	  break;  // branch content in register
	}
      break;
    case OPRegImm:
      switch (insn & OPRegImm_MASK)
	{
	case BLTZ:                      // Instructions from Table A-15
	case BGEZ:
	case BLTZAL:
	case BGEZAL:
	case BLTZL:
	case BGEZL:
	case BLTZALL:
	case BGEZALL:
	  // Added to the address of the instruction *following* the branch
	  offset = IMM(insn);
	  if (offset & IMM_SIGN) { offset |= ~IMM_MASK; } // sign extend
	  return ((pc + MINSN_SIZE) + (offset << 2));
	}
      break;

    // Normal instruction class
    case J:                             // Instructions from Table A-12
    case JAL:
      // These are PC-Region and not PC-Relative instructions.
      // Upper order bits come from the address of the delay-slot instruction
      offset = INSN_INDEX(insn) << 2;
      return (((pc + MINSN_SIZE) & INSN_INDEX_UPPER_MASK) | offset);

    case BEQ:                           // Instructions from Table A-14
    case BNE:
    case BLEZ:
    case BGTZ:
    case BEQL:
    case BNEL:
    case BLEZL:
    case BGTZL:
      // Added to the address of the instruction *following* the branch
      offset = IMM(insn);
      if (offset & IMM_SIGN) { offset |= ~IMM_MASK; } // sign extend
      return ((pc + MINSN_SIZE) + (offset << 2));

    default:
      break;
    }

  return (0);
}

ushort
MipsISA::GetInsnNumDelaySlots(MachInsn* mi, ushort opIndex, ushort sz)
{
  // All branches have an architectural delay of one
  // instruction. Treat branch-likely instructions as regular
  // branches.

  // (We don't care about delays on instructions such as loads/stores)
  InsnDesc d = GetInsnDesc(mi, opIndex, sz);
  if (d.IsBr() || d.IsSubr() || d.IsSubrRet()) {
    return 1;
  }
  else {
    return 0;
  }
}

void
MipsISA::decode(ostream& os, MachInsn* mi, VMA vma, ushort opIndex)
{
  m_dis_data.insn_addr = mi;
  m_dis_data.insn_vma = vma;

  m_di_dis->stream = (void*)&os;
  BFD_PRINT_INSN_MIPS(PTR_TO_BFDVMA(mi), m_di_dis);
}

//****************************************************************************
<commit_msg>minor update.<commit_after>// -*-Mode: C++;-*-
// $Id$

// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002-2007, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************
//
// File:
//   $Source$
//
// Purpose:
//   [The purpose of this file]
//
// Description:
//   [The set of functions, macros, etc. defined in the file]
//
//***************************************************************************

//************************* System Include Files ****************************

#include <iostream>
using std::ostream;

//*************************** User Include Files ****************************

#include <include/general.h>
#include <include/gnu_bfd.h>  // for bfd_getb32, bfd_getl32
#include <include/gnu_dis-asm.h>

#include "MipsISA.hpp"
#include "instructionSets/mips.h"

#include <lib/support/diagnostics.h>

//*************************** Forward Declarations ***************************

#if defined(HOST_PLATFORM_MIPS64LE_LINUX)
# define BFD_GETX32 bfd_getl32
# define BFD_PRINT_INSN_MIPS print_insn_little_mips
#else /* PLATFORM_MIPS_IRIX64 */
# define BFD_GETX32 bfd_getb32
# define BFD_PRINT_INSN_MIPS print_insn_big_mips
#endif

//****************************************************************************

static VMA
GNUvma2vma(bfd_vma di_vma, MachInsn* insn_addr, VMA insn_vma)
{
  // N.B.: The GNU decoders assume that the address of 'insn_addr' is
  // the actual the VMA in order to calculate VMA-relative targets.
  VMA x = (di_vma - PTR_TO_BFDVMA(insn_addr)) + insn_vma;
  return x;
}

static void
GNUbu_print_addr(bfd_vma di_vma, struct disassemble_info* di)
{
  GNUbu_disdata* data = (GNUbu_disdata*)di->application_data;

  VMA x = GNUvma2vma(di_vma, data->insn_addr, data->insn_vma);
  ostream* os = (ostream*)di->stream;
  *os << std::showbase << std::hex << x << std::dec;
}

//****************************************************************************
// MipsISA
//****************************************************************************

// See 'ISA.h' for comments on the interface

MipsISA::MipsISA()
  : m_di(NULL), m_di_dis(NULL)
{
  // See 'dis-asm.h'
  m_di = new disassemble_info;
  init_disassemble_info(m_di, stdout, GNUbu_fprintf_stub);
  m_di->arch = bfd_arch_mips;        // bfd_get_arch(abfd)
  m_di->mach = bfd_mach_mipsisa64r2; // bfd_get_mach(abfd)
#if defined(HOST_PLATFORM_MIPS64LE_LINUX)
  m_di->endian = BFD_ENDIAN_LITTLE;
#else
  m_di->endian = BFD_ENDIAN_BIG;
#endif
  m_di->read_memory_func = GNUbu_read_memory; // vs. 'buffer_read_memory'
  m_di->print_address_func = GNUbu_print_addr_stub; // vs. 'generic_print_addr'

  m_di_dis = new disassemble_info;
  init_disassemble_info(m_di_dis, stdout, GNUbu_fprintf);
  m_di_dis->application_data = (void*)&m_dis_data;
  m_di_dis->arch = m_di->arch;
  m_di_dis->mach = m_di->mach;
  m_di_dis->endian = m_di->endian;
  m_di_dis->read_memory_func = GNUbu_read_memory;
  m_di_dis->print_address_func = GNUbu_print_addr;
}

MipsISA::~MipsISA()
{
  delete m_di;
  delete m_di_dis;
}

ISA::InsnDesc
MipsISA::GetInsnDesc(MachInsn* mi, ushort opIndex, ushort sz)
{
  // We know that instruction sizes are guaranteed to be 4 bytes, but
  // the host may have a different byte order than the executable.
  uint32_t insn = (uint32_t)BFD_GETX32((const unsigned char*)mi);

  switch (insn & OP_MASK)
    {
    case OPSpecial:
      switch (insn & OPSpecial_MASK)
	{
	case JR:                        // Instructions from Table A-13
	  // JR $31 returns from a JAL call instruction.
	  if (REG_S(insn) == REG_RA) {
	    return InsnDesc(InsnDesc::SUBR_RET);
	  }
	  else {
	    return InsnDesc(InsnDesc::BR_UN_COND_IND);
	  }
	case JALR:
	  return InsnDesc(InsnDesc::SUBR_IND);

	case SYSCALL:                   // Instructions from Table A-16,
	case BREAK:                     //   Table A-17
	case TGE:   // Trap-on-Condition...
	case TGEU:
	case TLT:
	case TLTU:
	case TEQ:
	case TNE:
	  return InsnDesc(InsnDesc::SYS_CALL);

	case SYNC:
	  return InsnDesc(InsnDesc::OTHER);
	}
      break;
    case OPRegImm:
      switch (insn & OPRegImm_MASK)
	{
	case BLTZ:                      // Instructions from Table A-15
	case BGEZ:
	case BLTZL:
	case BGEZL:
	  return InsnDesc(InsnDesc::INT_BR_COND_REL);

	case BLTZAL:  // Link
	case BGEZAL:  // Link
	case BLTZALL: // Link
	case BGEZALL: // Link
	  return InsnDesc(InsnDesc::SUBR_REL);

	case TGEI:                      // Instructions from Table A-18
	case TGEIU: // Trap-on-Condition...
	case TLTI:
	case TLTIU:
	case TEQI:
	case TNEI:
	  return InsnDesc(InsnDesc::OTHER);
	}
      break;
    case OPCop1x:
      switch (insn & OPCop1x_MASK)
	{
	case LWXC1: // Word	        // Instructions from Table A-7
	  return InsnDesc(InsnDesc::MEM_LOAD);
	case LDXC1: // Doubleword
	  return InsnDesc(InsnDesc::MEM_LOAD);
	case SWXC1: // Word
	  return InsnDesc(InsnDesc::MEM_STORE);
	case SDXC1: // Doubleword
	  return InsnDesc(InsnDesc::MEM_STORE);
	}
      break;

    // Normal instruction class (OPNormal)
    case LB:   // Byte                  // Instructions from Table A-3
    case LBU:  // Byte Unsigned         //  Table A-4, Table A-5, Table A-6
    case LH:   // Halfword
    case LHU:  // Halfword Unsigned
    case LW:   // Word
    case LWU:  // Word Unsigned
    case LWL:  // Word Left
    case LWR:  // Word Right
    case LL:   // Linked Word
    case LWC1: // Word
    case LWC2: // Word
      return InsnDesc(InsnDesc::MEM_LOAD);

    case LD:   // Doubleword
    case LDL:  // Doubleword Left
    case LDR:  // Doubleword Right
    case LLD:  // Linked Doubleword
    case LDC1: // Doubleword
    case LDC2: // Doubleword
      return InsnDesc(InsnDesc::MEM_LOAD); // Doubleword

    case SB:   // Byte
    case SH:   // Halfword
    case SW:   // Word
    case SWL:  // Word Left
    case SWR:  // Word Right
    case SC:   // Conditional Word
    case SWC1: // Word
    case SWC2: // Word
      return InsnDesc(InsnDesc::MEM_STORE);

    case SD:   // Doubleword
    case SDL:  // Doubleword Left
    case SDR:  // Doubleword Right
    case SCD:  // Conditional Doubleword
    case SDC1: // Doubleword
    case SDC2: // Doubleword
      return InsnDesc(InsnDesc::MEM_STORE); // Doubleword

                                        // Instructions from Table A-12
      // N.B.: These instructions are PC-region but we will treat them
      // as PC-relative
    case J:
      return InsnDesc(InsnDesc::BR_UN_COND_REL);
    case JAL:
      return InsnDesc(InsnDesc::SUBR_REL);

    case BEQ:                           // Instructions from Table A-14
      // If operands are the same then then there is no fall-thru branch.
      // Test for general case.
      if (REG_S(insn) == REG_T(insn))
	return InsnDesc(InsnDesc::BR_UN_COND_REL);
      else
	return InsnDesc(InsnDesc::INT_BR_COND_REL);
    case BNE:
    case BLEZ:
    case BGTZ:
    case BEQL:
    case BNEL:
    case BLEZL:
    case BGTZL:
      return InsnDesc(InsnDesc::INT_BR_COND_REL);

    default:
      break;
    }

  return InsnDesc(InsnDesc::OTHER);
}

VMA
MipsISA::GetInsnTargetVMA(MachInsn* mi, VMA pc, ushort opIndex, ushort sz)
{
  // We know that instruction sizes are guaranteed to be 4 bytes, but
  // the host may have a different byte order than the executable.
  uint32_t insn = (uint32_t)BFD_GETX32((const unsigned char*)mi);

  intptr_t offset;
  switch (insn & OP_MASK)
    {
    case OPSpecial:
      switch (insn & OPSpecial_MASK)
	{
	case JR:                        // Instructions from Table A-13
	case JALR:
	  break;  // branch content in register
	}
      break;
    case OPRegImm:
      switch (insn & OPRegImm_MASK)
	{
	case BLTZ:                      // Instructions from Table A-15
	case BGEZ:
	case BLTZAL:
	case BGEZAL:
	case BLTZL:
	case BGEZL:
	case BLTZALL:
	case BGEZALL:
	  // Added to the address of the instruction *following* the branch
	  offset = IMM(insn);
	  if (offset & IMM_SIGN) { offset |= ~IMM_MASK; } // sign extend
	  return ((pc + MINSN_SIZE) + (offset << 2));
	}
      break;

    // Normal instruction class
    case J:                             // Instructions from Table A-12
    case JAL:
      // These are PC-Region and not PC-Relative instructions.
      // Upper order bits come from the address of the delay-slot instruction
      offset = INSN_INDEX(insn) << 2;
      return (((pc + MINSN_SIZE) & INSN_INDEX_UPPER_MASK) | offset);

    case BEQ:                           // Instructions from Table A-14
    case BNE:
    case BLEZ:
    case BGTZ:
    case BEQL:
    case BNEL:
    case BLEZL:
    case BGTZL:
      // Added to the address of the instruction *following* the branch
      offset = IMM(insn);
      if (offset & IMM_SIGN) { offset |= ~IMM_MASK; } // sign extend
      return ((pc + MINSN_SIZE) + (offset << 2));

    default:
      break;
    }

  return (0);
}

ushort
MipsISA::GetInsnNumDelaySlots(MachInsn* mi, ushort opIndex, ushort sz)
{
  // All branches have an architectural delay of one
  // instruction. Treat branch-likely instructions as regular
  // branches.

  // (We don't care about delays on instructions such as loads/stores)
  InsnDesc d = GetInsnDesc(mi, opIndex, sz);
  if (d.IsBr() || d.IsSubr() || d.IsSubrRet()) {
    return 1;
  }
  else {
    return 0;
  }
}

void
MipsISA::decode(ostream& os, MachInsn* mi, VMA vma, ushort opIndex)
{
  m_dis_data.insn_addr = mi;
  m_dis_data.insn_vma = vma;

  m_di_dis->stream = (void*)&os;
  BFD_PRINT_INSN_MIPS(PTR_TO_BFDVMA(mi), m_di_dis);
}

//****************************************************************************
<|endoftext|>