home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 June / ccd0605.iso / LINUX / gopchop-1.1.7.tar.tar / gopchop-1.1.7.tar / gopchop-1.1.7 / src / Parser.cpp < prev    next >
C/C++ Source or Header  |  2004-02-29  |  9KB  |  420 lines

  1. /*
  2. #
  3. # Creates an in-memory interface to a file, with largefile support.
  4. # Uses mmap to make data available in a user-space memory window.
  5. #
  6. # $Id: Parser.cpp,v 1.17 2004/02/29 11:18:33 nemies Exp $
  7. #
  8. # Copyright (C) 2001-2003 Kees Cook
  9. # kees@outflux.net, http://outflux.net/
  10. # This program is free software; you can redistribute it and/or
  11. # modify it under the terms of the GNU General Public License
  12. # as published by the Free Software Foundation; either version 2
  13. # of the License, or (at your option) any later version.
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. # GNU General Public License for more details.
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21. # http://www.gnu.org/copyleft/gpl.html
  22. #
  23. */
  24.  
  25. #include "GOPchop.h"
  26. #include "Parser.h"
  27.  
  28. // FIXME: do config.h magic...
  29. #include <stdarg.h>
  30. #include <errno.h>
  31. #include <string.h>
  32.  
  33. #undef MEMORY_UPDATE
  34. #ifdef MEMORY_UPDATE
  35. # define MMAP_PROT    (PROT_READ|PROT_WRITE)
  36. # define OPEN_MODE    (O_RDWR)
  37. #else
  38. # define MMAP_PROT    (PROT_READ)
  39. # define OPEN_MODE    (O_RDONLY)
  40. #endif
  41.  
  42. Parser::Parser(size_t window)
  43. {
  44.     // set passed-in values
  45.     mmap_max = window;
  46.  
  47.     // set detected values
  48.     pagesize = getpagesize();
  49.  
  50.     // set values that "reset" depends on
  51.     filename = NULL;
  52.     fd = -1;
  53.     mmap_ptr = NULL;
  54.     mmap_len = 0;
  55.     mmap_offset = 0;
  56.     error = NULL;
  57.  
  58.     reset();
  59. }
  60.  
  61. void Parser::reset()
  62. {
  63.     if (filename)
  64.     {
  65.         free(filename);
  66.         filename = NULL;
  67.     }
  68.  
  69.     if (fd > -1)
  70.     {
  71.         close(fd);
  72.         fd = -1;
  73.     }
  74.     filesize = 0;
  75.  
  76.     if (mmap_ptr)
  77.     {
  78.         if (munmap(mmap_ptr, mmap_len))
  79.             perror("munmap");
  80.         mmap_ptr = NULL;
  81.         mmap_len = 0;
  82.         mmap_offset = 0;
  83.     }
  84.  
  85.     location = 0;
  86.     start = NULL;
  87.     report_errors = TRUE;
  88.     parsing_state=PARSER_STATE_UNLOADED;
  89.  
  90.     clearError();
  91. }
  92.  
  93. Parser::~Parser()
  94. {
  95.     reset();
  96. }
  97.  
  98. int Parser::getParsingState()
  99. {
  100.     return parsing_state;
  101. }
  102.  
  103. #define MIN(a,b)    ((a)<(b) ? (a) : (b))
  104. int Parser::init(char *pathname, void (*ticker) (char *, float))
  105. {
  106.     struct stat st;
  107.  
  108.     tick = ticker;
  109.  
  110.     // make sure we're not already running
  111.     if (filename || fd > -1 || mmap_ptr)
  112.     {
  113.         reset();
  114.         addError("%s", _("already initialized\n"));
  115.         return FALSE;
  116.     }
  117.  
  118.     // open file
  119.     if ((fd = open(pathname, OPEN_MODE)) < 0)
  120.     {
  121.         reset();
  122.         addError(_("cannot open '%s': %s\n"), pathname, strerror(errno));
  123. #ifdef MEMORY_UPDATE
  124.         addError("%s",
  125.                  _
  126.                  (" (write permissions are needed, but the original file won't be changed.)\n"));
  127. #endif
  128.         return FALSE;
  129.     }
  130.  
  131.     // get file size
  132.     if (fstat(fd, &st))
  133.     {
  134.         reset();
  135.         addError(_("cannot get file size: %s\n"), strerror(errno));
  136.         return FALSE;
  137.     }
  138.  
  139.     if (!S_ISREG(st.st_mode))
  140.     {
  141.         reset();
  142.         addError(_("'%s' is not a file!\n"), pathname);
  143.         return FALSE;
  144.     }
  145.  
  146.     filesize = st.st_size;
  147.  
  148.     mmap_len = MIN(mmap_max, filesize);
  149.  
  150.     if ((mmap_ptr = (uint8_t *) mmap(NULL, mmap_len, MMAP_PROT,
  151.                                      MAP_PRIVATE, fd, 0)) == MAP_FAILED)
  152.     {
  153.         reset();
  154.         addError("%s", _("cannot memory map file\n"));
  155.         return FALSE;
  156.     }
  157.  
  158.     filename = strdup(pathname);
  159.     start = mmap_ptr;
  160.     location = 0;
  161.  
  162.     parsing_state=PARSER_STATE_READY;
  163.  
  164.     return TRUE;
  165. }
  166.  
  167. char *Parser::getFilename()
  168. {
  169.     return filename;
  170. }
  171.  
  172. char *Parser::getError()
  173. {
  174.     return error;
  175. }
  176.  
  177. off_t Parser::getSize()
  178. {
  179.     return filesize;
  180. }
  181.  
  182. #define MAX(a,b)    ((a) > (b) ? (a) : (b))
  183.  
  184. uint8_t *Parser::bytesAvail(off_t location, size_t bytes)
  185. {
  186.     off_t pagedloc;
  187.     size_t pagedbytes;
  188.  
  189.     // make sure we're in bounds
  190.     if (!mmap_ptr || location > filesize || location + bytes > filesize)
  191.     {
  192.         /*
  193.            printf("%s",_("out of bounds\n"));
  194.            printf(_("filesize: %llu\n"),filesize);
  195.            printf(_("location: %llu\n"),location);
  196.            printf(_("bytes: %d\n"),bytes);
  197.          */
  198.         return NULL;
  199.     }
  200.  
  201.     // are we inbounds in current mmap region?
  202.     if (mmap_offset <= location && location + bytes <= mmap_offset + mmap_len)
  203.     {
  204.         start = mmap_ptr + (location - mmap_offset);
  205.         return start;
  206.     }
  207.  
  208.     // we're not inbounds, let's realign on page boundry, near "location"
  209.  
  210.     // get page-aligned location
  211.     pagedloc = location / pagesize;
  212.     pagedloc *= pagesize;
  213.  
  214.     // figure out our expected mmap window size
  215.     pagedbytes = MAX(mmap_max, (location - pagedloc) + bytes);
  216.     // mmap area too large
  217.     if (pagedbytes > mmap_max)
  218.     {
  219.         printf(_("mmap area too large (must increase window size!)\n"
  220.                  "pagedbytes: %d mmap_max: %d\n"
  221.                  "location: %llu pagedloc: %llu\n"
  222.                  "bytes: %d\n"),
  223.                pagedbytes, mmap_max, location, pagedloc, bytes);
  224.         return NULL;
  225.     }
  226.  
  227.     // unmmmap or fail
  228.     if (munmap(mmap_ptr, mmap_len))
  229.     {
  230.         printf("%s", _("munmap failed\n"));
  231.         reset();
  232.         addError("%s", _("munmap\n"));
  233.         return NULL;
  234.     }
  235.  
  236.     mmap_len = pagedbytes;
  237.     mmap_offset = pagedloc;
  238.  
  239.     // remmap or fail
  240.     if ((mmap_ptr = (uint8_t *) mmap(NULL, mmap_len, MMAP_PROT,
  241.                                      MAP_PRIVATE, fd,
  242.                                      mmap_offset)) == MAP_FAILED)
  243.     {
  244.         printf("%s", _("mmap failed\n"));
  245.         reset();
  246.         addError("%s", _("cannot memory map file\n"));
  247.         return NULL;
  248.     }
  249.     /*
  250.        fprintf(stderr,_("remapped %d from %llu @ 0x%08x\n"),
  251.        mmap_len, mmap_offset, (unsigned int)mmap_ptr);
  252.      */
  253.  
  254.     start = mmap_ptr + (location - mmap_offset);
  255.     return start;
  256. }
  257.  
  258. void Parser::clearError()
  259. {
  260.     if (error)
  261.     {
  262.         free(error);
  263.         error = NULL;
  264.     }
  265. }
  266.  
  267. void Parser::addError(const char *fmt, ...)
  268. {
  269.     char buf[1024];
  270.     va_list vaptr;
  271.     int len;
  272.     int leftoff = 0;
  273.  
  274.     if (!report_errors)
  275.         return;
  276.  
  277.     buf[0] = '\0';              // preterminate for fun
  278.  
  279.     va_start(vaptr, fmt);
  280.     vsnprintf(buf, 1024, fmt, vaptr);
  281.     va_end(vaptr);
  282.  
  283.     len = strlen(buf) + 1;      // one for NULL
  284.  
  285.     if (error)
  286.     {
  287.         leftoff = strlen(error);
  288.         len += leftoff;
  289.     }
  290.  
  291.     if (!(error = (char *) realloc(error, len)))
  292.     {
  293.         // if we can't get memory for an error, we probably
  294.         // can't do much of anything anyway.
  295.         perror("realloc");
  296.         exit(1);
  297.     }
  298.     error[leftoff] = '\0';      // terminate our (possibly) new memory
  299.  
  300.     // this is safe now, since we used add's len to allocate it
  301.     strcat(error, buf);
  302.  
  303.     // send out the stderr too
  304.     fprintf(stderr, buf);
  305. }
  306.  
  307. int Parser::consume(size_t bytes, uint8_t * match)
  308. {
  309.     // no bytes?  SURE!
  310.     if (!bytes)
  311.         return TRUE;
  312.  
  313.     if (!bytesAvail(location, bytes) || memcmp(start, match, bytes))
  314.         return FALSE;
  315.  
  316.     start += bytes;
  317.     location += bytes;
  318.  
  319.     return TRUE;
  320. }
  321.  
  322. int Parser::verify(uint8_t * source, size_t bytes, uint8_t * match)
  323. {
  324.     // no bytes?  SURE!
  325.     if (!bytes)
  326.         return TRUE;
  327.  
  328.     if (memcmp(source, match, bytes) == 0)
  329.         return TRUE;
  330.     return FALSE;
  331. }
  332.  
  333. // Returns "start" before incrementing by "bytes"
  334. uint8_t *Parser::attach(size_t bytes)
  335. {
  336.     uint8_t *ptr;
  337.  
  338.     if ((ptr = examine(bytes)))
  339.     {
  340.         start += bytes;
  341.         location += bytes;
  342.     }
  343.  
  344.     return ptr;
  345. }
  346.  
  347. // returns points to memory but does not increment
  348. uint8_t *Parser::examine(size_t bytes)
  349. {
  350.     uint8_t *ptr = NULL;
  351.  
  352.     // no bytes? bad...
  353.     if (bytes && bytesAvail(location, bytes))
  354.     {
  355.         ptr = start;
  356.     }
  357.  
  358.     return ptr;
  359. }
  360.  
  361. // Checks for "bytes" many bytes into the future to match "match"
  362. int Parser::forwardMatch(size_t bytes, uint8_t * match)
  363. {
  364.     // no bytes?  SURE!
  365.     if (!bytes)
  366.         return TRUE;
  367.  
  368.     if (bytesAvail(location, bytes) && !memcmp(start, match, bytes))
  369.     {
  370.         return TRUE;
  371.     }
  372.     else
  373.         return FALSE;
  374. }
  375.  
  376. // Checks for up to 8 bits in the next byte, matching "value"
  377. int Parser::forwardBitMatch(int bits, uint8_t value)
  378. {
  379.     uint8_t match;
  380.     uint8_t mask;
  381.  
  382.     // 0 bits?  SURE!
  383.     if (!bits)
  384.         return TRUE;
  385.  
  386.     if (!bytesAvail(location, 1))
  387.         return FALSE;
  388.  
  389.     match = value << (8 - bits);
  390.     mask = (0xFF >> (8 - bits)) << (8 - bits);
  391.  
  392.     /*
  393.        int result=((*start & mask) == match);
  394.        printf(_("*start: %d mask: %d match: %d result: %d\n"),
  395.        *start, mask, match, result);
  396.      */
  397.  
  398.     return ((*start & mask) == match);
  399. }
  400.  
  401. // external access to the parsing state.  This can only be set if 
  402. // Parser is "READY" or "PARSING".  Once set to "FINISHED", it must
  403. // be ->reset to clear it.
  404. void Parser::setParsingState(int state)
  405. {
  406.     if ((parsing_state==PARSER_STATE_READY &&
  407.          state==PARSER_STATE_PARSING) ||
  408.         (parsing_state==PARSER_STATE_PARSING &&
  409.          state==PARSER_STATE_FINISHED))
  410.     {
  411.         parsing_state=state;
  412.     }
  413. }
  414.  
  415.  
  416. /* vi:set ai ts=4 sw=4 expandtab: */
  417.