[
  {
    "path": ".environmentLinux.yaml",
    "content": "name: foo\nchannels:\n  - conda-forge\n  - bioconda\n  - default\ndependencies:\n  - gcc_linux-64\n  - curl\n  - zlib\n  - python = 3.9\n  - pip\n  - numpy\n  - pytest"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Test\non: \n  pull_request:\n  push:\n\njobs:\n  testLinux:\n    name: Test Conda Linux\n    runs-on: \"ubuntu-latest\"\n    defaults:\n      run:\n        shell: bash -l {0}\n    steps:\n      - uses: actions/checkout@v2\n      - uses: conda-incubator/setup-miniconda@v2\n        with:\n          activate-environment: foo\n          environment-file: .environmentLinux.yaml\n          python-version: 3.9\n          auto-activate-base: false\n      - run: |\n          pip install .\n          pytest pyBigWigTest/test.py\n\n  test-builds:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: Set up Python\n      uses: actions/setup-python@v4\n      with:\n        python-version: '3.9'   \n    - name: Install build prerequisites\n      run: |\n        python -m pip install --upgrade build numpy\n    - name: Install cibuildwheel\n      run: |\n        python -m pip install --upgrade cibuildwheel      \n    - name: Build wheel(s)\n      run: |\n        python -m cibuildwheel --output-dir wheelhouse\n    - name: Build sdist\n      run: |\n        python -m build --sdist\n    - uses: actions/upload-artifact@v6\n      with:\n        name: pyBigWig-build\n        path: |\n          wheelhouse/*\n          dist/pyBigWig*.tar.gz\n"
  },
  {
    "path": ".github/workflows/pypi.yml",
    "content": "name: pypi\non: [push]\njobs:\n  pypi:\n    name: upload to pypi\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n      with:\n        fetch-depth: 0\n    - name: Set up Python\n      uses: actions/setup-python@v4\n      with:\n        python-version: '3.9'\n    - name: Install build prerequisites\n      if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')\n      run: |\n        python -m pip install --upgrade twine build cibuildwheel numpy \n    - name: sdist\n      if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')\n      run: |\n        python -m build --sdist\n    - name: wheel\n      if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')\n      run: |\n        python -m cibuildwheel --output-dir wheelhouse\n    - name: upload\n      if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')\n      env:\n        TWINE_USERNAME: \"__token__\"\n        TWINE_PASSWORD: ${{ secrets.pypi_password }}\n      run: |\n        twine upload dist/*\n        twine upload wheelhouse/*\n"
  },
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*,cover\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n*.o\n#./setup.py sdist creates this\nMANIFEST\n\n*.swp\n"
  },
  {
    "path": ".gitmodules",
    "content": ""
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Devon Ryan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include *.h\ninclude **/*.h\n"
  },
  {
    "path": "README.md",
    "content": "[![PyPI version](https://badge.fury.io/py/pyBigWig.svg)](https://badge.fury.io/py/pyBigWig) [![Travis-CI status](https://travis-ci.org/deeptools/pyBigWig.svg?branch=master)](https://travis-ci.org/dpryan79/pyBigWig.svg?branch=master) [![bioconda-badge](https://img.shields.io/badge/install%20with-bioconda-brightgreen.svg)](http://bioconda.github.io) [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.45238.svg)](http://dx.doi.org/10.5281/zenodo.45238)\n\n# pyBigWig\nA python extension, written in C, for quick access to bigBed files and access to and creation of bigWig files. This extension uses [libBigWig](https://github.com/dpryan79/libBigWig) for local and remote file access.\n\nTable of Contents\n=================\n\n  * [Installation](#installation)\n    * [Requirements](#requirements)\n  * [Usage](#usage)\n    * [Load the extension](#load-the-extension)\n    * [Open a bigWig or bigBed file](#open-a-bigwig-or-bigbed-file)\n    * [Determining the file type](#determining-the-file-type)\n    * [Access the list of chromosomes and their lengths](#access-the-list-of-chromosomes-and-their-lengths)\n    * [Print the header](#print-the-header)\n    * [Compute summary information on a range](#compute-summary-information-on-a-range)\n      * [A note on statistics and zoom levels](#a-note-on-statistics-and-zoom-levels)\n    * [Retrieve values for individual bases in a range](#retrieve-values-for-individual-bases-in-a-range)\n    * [Retrieve all intervals in a range](#retrieve-all-intervals-in-a-range)\n    * [Retrieving bigBed entries](#retrieving-bigbed-entries)\n    * [Add a header to a bigWig file](#add-a-header-to-a-bigwig-file)\n    * [Adding entries to a bigWig file](#adding-entries-to-a-bigwig-file)\n    * [Close a bigWig or bigBed file](#close-a-bigwig-or-bigbed-file)\n  * [Numpy](#numpy)\n  * [Remote file access](#remote-file-access)\n  * [Empty files](#empty-files)\n  * [A note on coordinates](#a-note-on-coordinates)\n  * [Galaxy](#galaxy)\n\n# Installation\nYou can install this extension directly from github with:\n\n    pip install pyBigWig\n\nor with conda\n\n    conda install pybigwig -c conda-forge -c bioconda\n\n## Requirements\n\nThe follow non-python requirements must be installed:\n\n - libcurl (and the `curl-config` config)\n - zlib\n\nThe headers and libraries for these are required.\n\n# Usage\nBasic usage is as follows:\n\n## Load the extension\n\n    >>> import pyBigWig\n\n## Open a bigWig or bigBed file\n\nThis will work if your working directory is the pyBigWig source code directory.\n\n    >>> bw = pyBigWig.open(\"test/test.bw\")\n\nNote that if the file doesn't exist you'll see an error message and `None` will be returned. Be default, all files are opened for reading and not writing. You can alter this by passing a mode containing `w`:\n\n    >>> bw = pyBigWig.open(\"test/output.bw\", \"w\")\n\nNote that a file opened for writing can't be queried for its intervals or statistics, it can *only* be written to. If you open a file for writing then you will next need to add a header (see the section on this below).\n\nLocal and remote bigBed read access is also supported:\n\n    >>> bb = pyBigWig.open(\"https://www.encodeproject.org/files/ENCFF001JBR/@@download/ENCFF001JBR.bigBed\")\n\nWhile you can specify a mode for bigBed files, it is ignored. The object returned by `pyBigWig.open()` is the same regardless of whether you're opening a bigWig or bigBed file.\n\n## Determining the file type\n\nSince bigWig and bigBed files can both be opened, it may be necessary to determine whether a given `bigWigFile` object points to a bigWig or bigBed file. To that end, one can use the `isBigWig()` and `isBigBed()` functions:\n\n    >>> bw = pyBigWig.open(\"test/test.bw\")\n    >>> bw.isBigWig()\n    True\n    >>> bw.isBigBed()\n    False\n\n## Access the list of chromosomes and their lengths\n\n`bigWigFile` objects contain a dictionary holding the chromosome lengths, which can be accessed with the `chroms()` accessor.\n\n    >>> bw.chroms()\n    dict_proxy({'1': 195471971L, '10': 130694993L})\n\nYou can also directly query a particular chromosome.\n\n    >>> bw.chroms(\"1\")\n    195471971L\n\nThe lengths are stored a the \"long\" integer type, which is why there's an `L` suffix. If you specify a non-existant chromosome then nothing is output.\n\n    >>> bw.chroms(\"c\")\n    >>> \n\n## Print the header\n\nIt's sometimes useful to print a bigWig's header. This is presented here as a python dictionary containing: the version (typically `4`), the number of zoom levels (`nLevels`), the number of bases described (`nBasesCovered`), the minimum value (`minVal`), the maximum value (`maxVal`), the sum of all values (`sumData`), and the sum of all squared values (`sumSquared`). The last two of these are needed for determining the mean and standard deviation.\n\n    >>> bw.header()\n    {'maxVal': 2L, 'sumData': 272L, 'minVal': 0L, 'version': 4L, 'sumSquared': 500L, 'nLevels': 1L, 'nBasesCovered': 154L}\n\nNote that this is also possible for bigBed files and the same dictionary keys will be present. Entries such as `maxVal`, `sumData`, `minVal`, and `sumSquared` are then largely not meaningful.\n\n## Compute summary information on a range\n\nbigWig files are used to store values associated with positions and ranges of them. Typically we want to quickly access the average value over a range, which is very simple:\n\n    >>> bw.stats(\"1\", 0, 3)\n    [0.2000000054637591]\n\nSuppose instead of the mean value, we instead wanted the maximum value:\n\n    >>> bw.stats(\"1\", 0, 3, type=\"max\")\n    [0.30000001192092896]\n\nOther options are \"min\" (the minimum value), \"coverage\" (the fraction of bases covered), and \"std\" (the standard deviation of the values).\n\nIt's often the case that we would instead like to compute values of some number of evenly spaced bins in a given interval, which is also simple:\n\n    >>> bw.stats(\"1\",99, 200, type=\"max\", nBins=2)\n    [1.399999976158142, 1.5]\n\n`nBins` defaults to 1, just as `type` defaults to `mean`.\n\nIf the start and end positions are omitted then the entire chromosome is used:\n\n    >>> bw.stats(\"1\")\n    [1.3351851569281683]\n\n### A note on statistics and zoom levels\n\n> A note to the lay reader: This section is rather technical and included only for the sake of completeness. The summary is that if your needs require exact mean/max/etc. summary values for an interval or intervals and that a small trade-off in speed is acceptable, that you should use the `exact=True` option in the `stats()` function.\n\nBy default, there are some unintuitive aspects to computing statistics on ranges in a bigWig file. The bigWig format was originally created in the context of genome browsers. There, computing exact summary statistics for a given interval is less important than quickly being able to compute an approximate statistic (after all, browsers need to be able to quickly display a number of contiguous intervals and support scrolling/zooming). Because of this, bigWig files contain not only interval-value associations, but also `sum of values`/`sum of squared values`/`minimum value`/`maximum value`/`number of bases covered` for equally sized bins of various sizes. These different sizes are referred to as \"zoom levels\". The smallest zoom level has bins that are 16 times the mean interval size in the file and each subsequent zoom level has bins 4 times larger than the previous. This methodology is used in Kent's tools and, therefore, likely used in almost every currently existing bigWig file.\n\nWhen a bigWig file is queried for a summary statistic, the size of the interval is used to determine whether to use a zoom level and, if so, which one. The optimal zoom level is that which has the largest bins no more than half the width of the desired interval. If no such zoom level exists, the original intervals are instead used for the calculation.\n\nFor the sake of consistency with other tools, pyBigWig adopts this same methodology. However, since this is (A) unintuitive and (B) undesirable in some applications, pyBigWig enables computation of exact summary statistics regardless of the interval size (i.e., it allows ignoring the zoom levels). This was originally proposed [here](https://github.com/dpryan79/pyBigWig/issues/12) and an example is below:\n\n    >>> import pyBigWig\n    >>> from numpy import mean\n    >>> bw = pyBigWig.open(\"http://hgdownload.cse.ucsc.edu/goldenPath/hg19/encodeDCC/wgEncodeMapability/wgEncodeCrgMapabilityAlign75mer.bigWig\")\n    >>> bw.stats('chr1', 89294, 91629)\n    [0.20120902053804418]\n    >>> mean(bw.values('chr1', 89294, 91629))\n    0.22213841940688142\n    >>> bw.stats('chr1', 89294, 91629, exact=True)\n    [0.22213841940688142]\n\n## Retrieve values for individual bases in a range\n\nWhile the `stats()` method **can** be used to retrieve the original values for each base (e.g., by setting `nBins` to the number of bases), it's preferable to instead use the `values()` accessor.\n\n    >>> bw.values(\"1\", 0, 3)\n    [0.10000000149011612, 0.20000000298023224, 0.30000001192092896]\n\nThe list produced will always contain one value for every base in the range specified. If a particular base has no associated value in the bigWig file then the returned value will be `nan`.\n\n    >>> bw.values(\"1\", 0, 4)\n    [0.10000000149011612, 0.20000000298023224, 0.30000001192092896, nan]\n\n## Retrieve all intervals in a range\n\nSometimes it's convenient to retrieve all entries overlapping some range. This can be done with the `intervals()` function:\n\n    >>> bw.intervals(\"1\", 0, 3)\n    ((0, 1, 0.10000000149011612), (1, 2, 0.20000000298023224), (2, 3, 0.30000001192092896))\n\nWhat's returned is a list of tuples containing: the start position, end end position, and the value. Thus, the example above has values of `0.1`, `0.2`, and `0.3` at positions `0`, `1`, and `2`, respectively.\n\nIf the start and end position are omitted then all intervals on the chromosome specified are returned:\n\n    >>> bw.intervals(\"1\")\n    ((0, 1, 0.10000000149011612), (1, 2, 0.20000000298023224), (2, 3, 0.30000001192092896), (100, 150, 1.399999976158142), (150, 151, 1.5))\n\n## Retrieving bigBed entries\n\nAs opposed to bigWig files, bigBed files hold entries, which are intervals with an associated string. You can access these entries using the `entries()` function:\n\n    >>> bb = pyBigWig.open(\"https://www.encodeproject.org/files/ENCFF001JBR/@@download/ENCFF001JBR.bigBed\")\n    >>> bb.entries('chr1', 10000000, 10020000)\n    [(10009333, 10009640, '61035\\t130\\t-\\t0.026\\t0.42\\t404'), (10014007, 10014289, '61047\\t136\\t-\\t0.029\\t0.42\\t404'), (10014373, 10024307, '61048\\t630\\t-\\t5.420\\t0.00\\t2672399')]\n\nThe output is a list of entry tuples. The tuple elements are the `start` and `end` position of each entry, followed by its associated `string`. The string is returned exactly as it's held in the bigBed file, so parsing it is left to you. To determine what the various fields are in these string, consult the SQL string:\n\n    >>> bb.SQL()\n    table RnaElements\n    \"BED6 + 3 scores for RNA Elements data\"\n        (\n        string chrom;      \"Reference sequence chromosome or scaffold\"\n        uint   chromStart; \"Start position in chromosome\"\n        uint   chromEnd;   \"End position in chromosome\"\n        string name;       \"Name of item\"\n        uint   score;      \"Normalized score from 0-1000\"\n        char[1] strand;    \"+ or - or . for unknown\"\n        float level;       \"Expression level such as RPKM or FPKM. Set to -1 for no data.\"\n        float signif;      \"Statistical significance such as IDR. Set to -1 for no data.\"\n        uint score2;       \"Additional measurement/count e.g. number of reads. Set to 0 for no data.\"\n        )\n\nNote that the first three entries in the SQL string are not part of the string.\n\nIf you only need to know where entries are and not their associated values, you can save memory by additionally specifying `withString=False` in `entries()`:\n\n    >>> bb.entries('chr1', 10000000, 10020000, withString=False)\n    [(10009333, 10009640), (10014007, 10014289), (10014373, 10024307)]\n\n## Add a header to a bigWig file\n\nIf you've opened a file for writing then you'll need to give it a header before you can add any entries. The header contains all of the chromosomes, **in order**, and their sizes. If your genome has two chromosomes, chr1 and chr2, of lengths 1 and 1.5 million bases, then the following would add an appropriate header:\n\n    >>> bw.addHeader([(\"chr1\", 1000000), (\"chr2\", 1500000)])\n\nbigWig headers are case-sensitive, so `chr1` and `Chr1` are different. Likewise, `1` and `chr1` are not the same, so you can't mix Ensembl and UCSC chromosome names. After adding a header, you can then add entries.\n\nBy default, up to 10 \"zoom levels\" are constructed for bigWig files. You can change this default number with the `maxZooms` optional argument. A common use of this is to create a bigWig file that simply holds intervals and no zoom levels:\n\n    >>> bw.addHeader([(\"chr1\", 1000000), (\"chr2\", 1500000)], maxZooms=0)\n\nIf you set `maxTooms=0`, please note that IGV and many other tools WILL NOT WORK as they assume that at least one zoom level will be present. You are advised to use the default unless you do not expect the bigWig files to be used by other packages.\n\n## Adding entries to a bigWig file\n\nAssuming you've opened a file for writing and added a header, you can then add entries. Note that the entries **must** be added in order, as bigWig files always contain ordered intervals. There are three formats that bigWig files can use internally to store entries. The most commonly observed format is identical to a [bedGraph](https://genome.ucsc.edu/goldenpath/help/bedgraph.html) file:\n\n    chr1\t0\t100\t0.0\n    chr1\t100\t120\t1.0\n    chr1\t125\t126\t200.0\n\nThese entries would be added as follows:\n\n    >>> bw.addEntries([\"chr1\", \"chr1\", \"chr1\"], [0, 100, 125], ends=[5, 120, 126], values=[0.0, 1.0, 200.0])\n\nEach entry occupies 12 bytes before compression.\n\nThe second format uses a fixed span, but a variable step size between entries. These can be represented in a [wiggle](http://genome.ucsc.edu/goldenpath/help/wiggle.html) file as:\n\n    variableStep chrom=chr1 span=20\n    500\t-2.0\n    600\t150.0\n    635\t25.0\n\nThe above entries describe (1-based) positions 501-520, 601-620 and 636-655. These would be added as follows:\n\n    >>> bw.addEntries(\"chr1\", [500, 600, 635], values=[-2.0, 150.0, 25.0], span=20)\n\nEach entry of this type occupies 8 bytes before compression.\n\nThe final format uses a fixed step and span for each entry, corresponding to the fixedStep [wiggle format](http://genome.ucsc.edu/goldenpath/help/wiggle.html):\n\n    fixedStep chrom=chr1 step=30 span=20\n    -5.0\n    -20.0\n    25.0\n\nThe above entries describe (1-based) bases 901-920, 931-950 and 961-980 and would be added as follows:\n\n    >>> bw.addEntries(\"chr1\", 900, values=[-5.0, -20.0, 25.0], span=20, step=30)\n\nEach entry of this type occupies 4 bytes.\n\nNote that pyBigWig will try to prevent you from adding entries in an incorrect order. This, however, requires additional over-head. Should that not be acceptable, you can simply specify `validate=False` when adding entries:\n\n    >>> bw.addEntries([\"chr1\", \"chr1\", \"chr1\"], [100, 0, 125], ends=[120, 5, 126], values=[0.0, 1.0, 200.0], validate=False)\n\nYou're obviously then responsible for ensuring that you **do not** add entries out of order. The resulting files would otherwise largley not be usable.\n\n## Close a bigWig or bigBed file\n\nA file can be closed with a simple `bw.close()`, as is commonly done with other file types. For files opened for writing, closing a file writes any buffered entries to disk, constructs and writes the file index, and constructs zoom levels. Consequently, this can take a bit of time.\n\n# Numpy\n\nAs of version 0.3.0, pyBigWig supports input of coordinates using numpy integers and vectors in some functions **if numpy was installed prior to installing pyBigWig**. To determine if pyBigWig was installed with numpy support by checking the `numpy` accessor:\n\n    >>> import pyBigWig\n    >>> pyBigWig.numpy\n    1\n\nIf `pyBigWig.numpy` is `1`, then pyBigWig was compiled with numpy support. This means that `addEntries()` can accept numpy coordinates:\n\n    >>> import pyBigWig\n    >>> import numpy\n    >>> bw = pyBigWig.open(\"/tmp/delete.bw\", \"w\")\n    >>> bw.addHeader([(\"1\", 1000)], maxZooms=0)\n    >>> chroms = np.array([\"1\"] * 10)\n    >>> starts = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90], dtype=np.int64)\n    >>> ends = np.array([5, 15, 25, 35, 45, 55, 65, 75, 85, 95], dtype=np.int64)\n    >>> values0 = np.array(np.random.random_sample(10), dtype=np.float64)\n    >>> bw.addEntries(chroms, starts, ends=ends, values=values0)\n    >>> bw.close()\n\nAdditionally, `values()` can directly output a numpy vector:\n\n    >>> bw = bw.open(\"/tmp/delete.bw\")\n    >>> bw.values('1', 0, 10, numpy=True)\n    [ 0.74336642  0.74336642  0.74336642  0.74336642  0.74336642         nan\n         nan         nan         nan         nan]\n    >>> type(bw.values('1', 0, 10, numpy=True))\n    <type 'numpy.ndarray'>\n\n# Remote file access\n\nIf you do not have curl installed, pyBigWig will be installed without the ability to access remote files. You can determine if you will be able to access remote files with `pyBigWig.remote`. If that returns 1, then you can access remote files. If it returns 0 then you can't.\n\n# Empty files\n\nAs of version 0.3.5, pyBigWig is able to read and write bigWig files lacking entries. Please note that such files are generally not compatible with other programs, since there's no definition of how a bigWig file with no entries should look. For such a file, the `intervals()` accessor will return `None`, the `stats()` function will return a list of `None` of the desired length, and `values()` will return `[]` (an empty list). This should generally allow programs utilizing pyBigWig to continue without issue.\n\nFor those wishing to mimic the functionality of pyBigWig/libBigWig in this regard, please note that it looks at the number of bases covered (as reported in the file header) to check for \"empty\" files.\n\n# A note on coordinates\n\nWiggle, bigWig, and bigBed files use 0-based half-open coordinates, which are also used by this extension. So to access the value for the first base on `chr1`, one would specify the starting position as `0` and the end position as `1`. Similarly, bases 100 to 115 would have a start of `99` and an end of `115`. This is simply for the sake of consistency with the underlying bigWig file and may change in the future.\n\n# Galaxy\n\npyBigWig is also available as a package in [Galaxy](http://www.usegalaxy.org). You can find it in the toolshed and the [IUC](https://wiki.galaxyproject.org/IUC) is currently hosting the XML definition of this on [github](https://github.com/galaxyproject/tools-iuc/tree/master/packages/package_python_2_7_10_pybigwig_0_2_8).\n"
  },
  {
    "path": "libBigWig/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Devon Ryan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "libBigWig/README.md",
    "content": "![Master build status](https://travis-ci.org/dpryan79/libBigWig.svg?branch=master) [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.45278.svg)](http://dx.doi.org/10.5281/zenodo.45278)\n\nA C library for reading/parsing local and remote bigWig and bigBed files. While Kent's source code is free to use for these purposes, it's really inappropriate as library code since it has the unfortunate habit of calling `exit()` whenever there's an error. If that's then used inside of something like python then the python interpreter gets killed. This library is aimed at resolving these sorts of issues and should also use more standard things like curl and has a friendlier license to boot.\n\nDocumentation is automatically generated by doxygen and can be found under `docs/html` or online [here](https://cdn.rawgit.com/dpryan79/libBigWig/master/docs/html/index.html).\n\n# Example\n\nThe only functions and structures that end users need to care about are in \"bigWig.h\". Below is a commented example. You can see the files under `test/` for further examples.\n\n    #include \"bigWig.h\"\n    int main(int argc, char *argv[]) {\n        bigWigFile_t *fp = NULL;\n        bwOverlappingIntervals_t *intervals = NULL;\n        double *stats = NULL;\n        if(argc != 2) {\n            fprintf(stderr, \"Usage: %s {file.bw|URL://path/file.bw}\\n\", argv[0]);\n            return 1;\n        }\n\n        //Initialize enough space to hold 128KiB (1<<17) of data at a time\n        if(bwInit(1<<17) != 0) {\n            fprintf(stderr, \"Received an error in bwInit\\n\");\n            return 1;\n        }\n\n        //Open the local/remote file\n        fp = bwOpen(argv[1], NULL, \"r\");\n        if(!fp) {\n            fprintf(stderr, \"An error occurred while opening %s\\n\", argv[1]);\n            return 1;\n        }\n\n        //Get values in a range (0-based, half open) without NAs\n        intervals = bwGetValues(fp, \"chr1\", 10000000, 10000100, 0);\n        bwDestroyOverlappingIntervals(intervals); //Free allocated memory\n\n        //Get values in a range (0-based, half open) with NAs\n        intervals = bwGetValues(fp, \"chr1\", 10000000, 10000100, 1);\n        bwDestroyOverlappingIntervals(intervals); //Free allocated memory\n\n        //Get the full intervals that overlap\n        intervals = bwGetOverlappingIntervals(fp, \"chr1\", 10000000, 10000100);\n        bwDestroyOverlappingIntervals(intervals);\n\n        //Get an example statistic - standard deviation\n        //We want ~4 bins in the range\n        stats = bwStats(fp, \"chr1\", 10000000, 10000100, 4, dev);\n        if(stats) {\n            printf(\"chr1:10000000-10000100 std. dev.: %f %f %f %f\\n\", stats[0], stats[1], stats[2], stats[3]);\n            free(stats);\n        }\n\n        bwClose(fp);\n        bwCleanup();\n        return 0;\n    }\n\n##Writing example\n\nN.B., creation of bigBed files is not supported (there are no plans to change this).\n\nBelow is an example of how to write bigWig files. You can also find this file under `test/exampleWrite.c`. Unlike with Kent's tools, you can create bigWig files entry by entry without needing an intermediate wiggle or bedGraph file. Entries in bigWig files are stored in blocks with each entry in a block referring to the same chromosome and having the same type, of which there are three (see the [wiggle specification](http://genome.ucsc.edu/goldenpath/help/wiggle.html) for more information on this).\n\n    #include \"bigWig.h\"\n    \n    int main(int argc, char *argv[]) {\n        bigWigFile_t *fp = NULL;\n        char *chroms[] = {\"1\", \"2\"};\n        char *chromsUse[] = {\"1\", \"1\", \"1\"};\n        uint32_t chrLens[] = {1000000, 1500000};\n        uint32_t starts[] = {0, 100, 125,\n                             200, 220, 230,\n                             500, 600, 625,\n                             700, 800, 850};\n        uint32_t ends[] = {5, 120, 126,\n                           205, 226, 231};\n        float values[] = {0.0f, 1.0f, 200.0f,\n                          -2.0f, 150.0f, 25.0f,\n                          0.0f, 1.0f, 200.0f,\n                          -2.0f, 150.0f, 25.0f,\n                          -5.0f, -20.0f, 25.0f,\n                          -5.0f, -20.0f, 25.0f};\n        \n        if(bwInit(1<<17) != 0) {\n            fprintf(stderr, \"Received an error in bwInit\\n\");\n            return 1;\n        }\n    \n        fp = bwOpen(\"example_output.bw\", NULL, \"w\");\n        if(!fp) {\n            fprintf(stderr, \"An error occurred while opening example_output.bw for writingn\\n\");\n            return 1;\n        }\n    \n        //Allow up to 10 zoom levels, though fewer will be used in practice\n        if(bwCreateHdr(fp, 10)) goto error;\n    \n        //Create the chromosome lists\n        fp->cl = bwCreateChromList(chroms, chrLens, 2);\n        if(!fp->cl) goto error;\n    \n        //Write the header\n        if(bwWriteHdr(fp)) goto error;\n    \n        //Some example bedGraph-like entries\n        if(bwAddIntervals(fp, chromsUse, starts, ends, values, 3)) goto error;\n        //We can continue appending similarly formatted entries\n        //N.B. you can't append a different chromosome (those always go into different\n        if(bwAppendIntervals(fp, starts+3, ends+3, values+3, 3)) goto error;\n    \n        //Add a new block of entries with a span. Since bwAdd/AppendIntervals was just used we MUST create a new block\n        if(bwAddIntervalSpans(fp, \"1\", starts+6, 20, values+6, 3)) goto error;\n        //We can continue appending similarly formatted entries\n        if(bwAppendIntervalSpans(fp, starts+9, values+9, 3)) goto error;\n    \n        //Add a new block of fixed-step entries\n        if(bwAddIntervalSpanSteps(fp, \"1\", 900, 20, 30, values+12, 3)) goto error;\n        //The start is then 760, since that's where the previous step ended\n        if(bwAppendIntervalSpanSteps(fp, values+15, 3)) goto error;\n\n        //Add a new chromosome\n        chromsUse[0] = \"2\";\n        chromsUse[1] = \"2\";\n        chromsUse[2] = \"2\";\n        if(bwAddIntervals(fp, chromsUse, starts, ends, values, 3)) goto error;\n    \n        //Closing the file causes the zoom levels to be created\n        bwClose(fp);\n        bwCleanup();\n    \n        return 0;\n    \n    error:\n        fprintf(stderr, \"Received an error somewhere!\\n\");\n        bwClose(fp);\n        bwCleanup();\n        return 1;\n    }\n\n# Testing file types\n\nAs of version 0.3.0, this library supports accessing bigBed files, which are related to bigWig files. Applications that need to support both bigWig and bigBed input can use the `bwIsBigWig` and `bbIsBigBed` functions to determine if their inputs are bigWig/bigBed files:\n\n    ...code...\n    if(bwIsBigWig(input_file_name, NULL)) {\n        //do something\n    } else if(bbIsBigBed(input_file_name, NULL)) {\n        //do something else\n    } else {\n        //handle unknown input\n    }\n\nNote that these two functions rely on the \"magic number\" at the beginning of each file, which differs between bigWig and bigBed files.\n\n# bigBed support\n\nSupport for accessing bigBed files was added in version 0.3.0. The function names used for accessing bigBed files are similar to those used for bigWig files.\n\n    Function | Use\n    --- | ---\n    bbOpen | Opens a bigBed file\n    bbGetSQL | Returns the SQL string (if it exists) in a bigBed file\n    bbGetOverlappingEntries | Returns all entries overlapping an interval (either with or without their associated strings\n    bbDestroyOverlappingEntries | Free memory allocated by the above command\n\nOther functions, such as `bwClose` and `bwInit`, are shared between bigWig and bigBed files. See `test/testBigBed.c` for a full example.\n\n# A note on bigBed entries\n\nInside bigBed files, entries are stored as chromosome, start, and end coordinates with an (optional) associated string. For example, a \"bedRNAElements\" file from Encode has name, score, strand, \"level\", \"significance\", and \"score2\" values associated with each entry. These are stored inside the bigBed files as a single tab-separated character vector (char \\*), which makes parsing difficult. The names of the various fields inside of bigBed files is stored as an SQL string, for example:\n\n    table RnaElements \n    \"BED6 + 3 scores for RNA Elements data \"\n        (\n        string chrom;      \"Reference sequence chromosome or scaffold\"\n        uint   chromStart; \"Start position in chromosome\"\n        uint   chromEnd;   \"End position in chromosome\"\n        string name;       \"Name of item\"\n        uint   score;      \"Normalized score from 0-1000\"\n        char[1] strand;    \"+ or - or . for unknown\"\n        float level;       \"Expression level such as RPKM or FPKM. Set to -1 for no data.\"\n        float signif;      \"Statistical significance such as IDR. Set to -1 for no data.\"\n        uint score2;       \"Additional measurement/count e.g. number of reads. Set to 0 for no data.\"\n        )\n\nEntries will then be of the form (one per line):\n\n    59426\t115\t-\t0.021\t0.48\t218\n    51\t209\t+\t0.071\t0.74\t130\n    52\t170\t+\t0.045\t0.61\t171\n    59433\t178\t-\t0.049\t0.34\t296\n    53\t156\t+\t0.038\t0.19\t593\n    59436\t186\t-\t0.054\t0.15\t1010\n    59437\t506\t-\t1.560\t0.00\t430611\n\nNote that chromosome and start/end intervals are stored separately, so there's no need to parse them out of string. libBigWig can return these entries, either with or without the above associated strings. Parsing these string is left to the application requiring them and is currently outside the scope of this library.\n\n# Interval/Entry iterators\n\nSometimes it is desirable to request a large number of intervals from a bigWig file or entries from a bigBed file, but not hold them all in memory at once (e.g., due to saving memory). To support this, libBigWig (since version 0.3.0) supports two kinds of iterators. The general process of using iterators is: (1) iterator creation, (2) traversal, and finally (3) iterator destruction. Only iterator creation differs between bigWig and bigBed files.\n\nImportantly, iterators return results by one or more blocks. This is for convenience, since bigWig intervals and bigBed entries are stored in together in fixed-size groups, called blocks. The number of blocks of entries returned, therefore, is an option that can be specified to balance performance and memory usage.\n\n## Iterator creation\n\nFor bigwig files, iterators are created with the `bwOverlappingIntervalsIterator()`. This function takes chromosomal bounds (chromosome name, start, and end position) as well as a number of blocks. The equivalent function for bigBed files is `bbOverlappingEntriesIterator()`, which additionally takes a `withString` argutment, which dictates whether the returned entries include the associated string values or not.\n\nEach of the aforementioned files returns a pointer to a `bwOverlapIterator_t` object. The only important parts of this structure for end users are the following members: `entries`, `intervals`, and `data`. `entries` is a pointer to a `bbOverlappingEntries_t` object, or `NULL` if a bigWig file is being used. Likewise, `intervals` is a pointer to a `bwOverlappingIntervals_t` object, or `NULL` if a bigBed file is being used. `data` is a special pointer, used to signify the end of iteration. Thus, when `data` is a `NULL` pointer, iteration has ended.\n\n## Iterator traversal\n\nRegardless of whether a bigWig or bigBed file is being used, the `bwIteratorNext()` function will free currently used memory and load the appropriate intervals or entries for the next block(s). On error, this will return a NULL pointer (memory is already internally freed in this case).\n\n## Iterator destruction\n\n`bwOverlapIterator_t` objects MUST be destroyed after use. This can be done with the `bwIteratorDestroy()` function.\n\n## Example\n\nA full example is provided in `tests/testIterator.c`, but a small example of iterating over all bigWig intervals in `chr1:0-10000000` in chunks of 5 blocks follows:\n\n    iter = bwOverlappingIntervalsIterator(fp, \"chr1\", 0, 10000000, 5);\n    while(iter->data) {\n        //Do stuff with iter->intervals\n        iter = bwIteratorNext(iter);\n    }\n    bwIteratorDestroy(iter);\n\n# A note on bigWig statistics\n\nThe results of `min`, `max`, and `mean` should be the same as those from `BigWigSummary`. `stdev` and `coverage`, however, may differ due to Kent's tools producing incorrect results (at least for `coverage`, though the same appears to be the case for `stdev`).\n\n# Python interface\n\nThere are currently two python interfaces that make use of libBigWig: [pyBigWig](https://github.com/dpryan79/pyBigWig) by me and [bw-python](https://github.com/brentp/bw-python) by Brent Pederson. Those interested are encouraged to give both a try!\n"
  },
  {
    "path": "libBigWig/bigWig.h",
    "content": "#ifndef LIBBIGWIG_H\n#define LIBBIGWIG_H\n\n#include \"bigWigIO.h\"\n#include \"bwValues.h\"\n#include <inttypes.h>\n#include <zlib.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*! \\mainpage libBigWig\n *\n * \\section Introduction\n *\n * libBigWig is a C library for parsing local/remote bigWig and bigBed files. This is similar to Kent's library from UCSC, except \n *  * The license is much more liberal\n *  * This code doesn't call `exit()` on error, thereby killing the calling application.\n *\n * External files are accessed using [curl](http://curl.haxx.se/).\n *\n * Please submit issues and pull requests [here](https://github.com/dpryan79/libBigWig).\n *\n * \\section Compilation\n *\n * Assuming you already have the curl libraries installed (not just the curl binary!):\n *\n *     make install prefix=/some/path\n *\n * \\section Writing bigWig files\n *\n * There are three methods for storing values in a bigWig file, further described in the [wiggle format](http://genome.ucsc.edu/goldenpath/help/wiggle.html). The entries within the file are grouped into \"blocks\" and each such block is limited to storing entries of a single type. So, it is unwise to use a single bedGraph-like endtry followed by a single fixed-step entry followed by a variable-step entry, as that would require three separate blocks, with additional space required for each.\n *\n * \\section Testing file types\n *\n * As of version 0.3.0, libBigWig supports reading bigBed files. If an application needs to support both bigBed and bigWig input, then the `bwIsBigWig` and `bbIsBigBed` functions can be used to determine the file type. These both use the \"magic\" number at the beginning of the file to determine the file type.\n *\n * \\section Interval and entry iterators\n *\n * As of version 0.3.0, libBigWig supports iterating over intervals in bigWig files and entries in bigBed files. The number of intervals/entries returned with each iteration can be controlled by setting the number of blocks processed in each iteration (intervals and entries are group inside of bigWig and bigBed files into blocks of entries). See `test/testIterator.c` for an example.\n *\n * \\section Examples\n * \n * Please see [README.md](README.md) and the files under `test/` for examples.\n */\n \n\n/*! \\file bigWig.h\n *\n * These are the functions and structured that should be used by external users. While I don't particularly recommend dealing with some of the structures (e.g., a bigWigHdr_t), they're described here in case you need them.\n *\n * BTW, this library doesn't switch endianness as appropriate, since I kind of assume that there's only one type produced these days.\n */\n\n/*!\n * The library version number\n */\n#define LIBBIGWIG_VERSION 0.4.8\n\n/*!\n * If 1, then this library was compiled with remote file support.\n */\n#ifdef NOCURL\n#define LIBBIGWIG_CURL 0\n#ifndef CURLTYPE_DEFINED\n#define CURLTYPE_DEFINED\ntypedef int CURLcode;\ntypedef void CURL;\n#endif\n#else\n#define LIBBIGWIG_CURL 1\n#endif\n\n/*!\n * The magic number of a bigWig file.\n */\n#define BIGWIG_MAGIC 0x888FFC26\n/*!\n * The magic number of a bigBed file.\n */\n#define BIGBED_MAGIC 0x8789F2EB\n/*!\n * The magic number of a \"cirTree\" block in a file.\n */\n#define CIRTREE_MAGIC 0x78ca8c91\n/*!\n * The magic number of an index block in a file.\n */\n#define IDX_MAGIC 0x2468ace0\n/*!\n * The default number of children per block.\n */\n#define DEFAULT_nCHILDREN 64\n/*!\n * The default decompression buffer size in bytes. This is used to determin\n */\n#define DEFAULT_BLOCKSIZE 32768\n\n/*!\n * An enum that dictates the type of statistic to fetch for a given interval\n */\nenum bwStatsType {\n    doesNotExist = -1, /*!< This does nothing */\n    mean = 0, /*!< The mean value */\n    average = 0, /*!< The mean value */\n    stdev = 1, /*!< The standard deviation of the values */\n    dev = 1, /*!< The standard deviation of the values */\n    max = 2, /*!< The maximum value */\n    min = 3, /*!< The minimum value */\n    cov = 4, /*!< The number of bases covered */\n    coverage = 4, /*!<The number of bases covered */ \n    sum = 5 /*!< The sum of per-base values */\n};\n\n//Should hide this from end users\n/*!\n * @brief BigWig files have multiple \"zoom\" levels, each of which has its own header. This hold those headers\n *\n * N.B., there's 4 bytes of padding in the on disk representation of level and dataOffset.\n */\ntypedef struct {\n    uint32_t *level; /**<The zoom level, which is an integer starting with 0.*/\n    //There's 4 bytes of padding between these\n    uint64_t *dataOffset; /**<The offset to the on-disk start of the data. This isn't used currently.*/\n    uint64_t *indexOffset; /**<The offset to the on-disk start of the index. This *is* used.*/\n    bwRTree_t **idx; /**<Index for each zoom level. Represented as a tree*/\n} bwZoomHdr_t;\n\n/*!\n * @brief The header section of a bigWig file.\n *\n * Some of the values aren't currently used for anything. Others may optionally not exist.\n */\ntypedef struct {\n    uint16_t version; /**<The version information of the file.*/\n    uint16_t nLevels; /**<The number of \"zoom\" levels.*/\n    uint64_t ctOffset; /**<The offset to the on-disk chromosome tree list.*/\n    uint64_t dataOffset; /**<The on-disk offset to the first block of data.*/\n    uint64_t indexOffset; /**<The on-disk offset to the data index.*/\n    uint16_t fieldCount; /**<Total number of fields.*/\n    uint16_t definedFieldCount; /**<Number of fixed-format BED fields.*/\n    uint64_t sqlOffset; /**<The on-disk offset to an SQL string. This is unused.*/\n    uint64_t summaryOffset; /**<If there's a summary, this is the offset to it on the disk.*/\n    uint32_t bufSize; /**<The compression buffer size (if the data is compressed).*/\n    uint64_t extensionOffset; /**<Unused*/\n    bwZoomHdr_t *zoomHdrs; /**<Pointers to the header for each zoom level.*/\n    //total Summary\n    uint64_t nBasesCovered; /**<The total bases covered in the file.*/\n    double minVal; /**<The minimum value in the file.*/\n    double maxVal; /**<The maximum value in the file.*/\n    double sumData; /**<The sum of all values in the file.*/\n    double sumSquared; /**<The sum of the squared values in the file.*/\n} bigWigHdr_t;\n\n//Should probably replace this with a hash\n/*!\n * @brief Holds the chromosomes and their lengths\n */\ntypedef struct {\n    int64_t nKeys; /**<The number of chromosomes */\n    char **chrom; /**<A list of null terminated chromosomes */\n    uint32_t *len; /**<The lengths of each chromosome */\n} chromList_t;\n\n//TODO remove from bigWig.h\n/// @cond SKIP\ntypedef struct bwLL bwLL;\nstruct bwLL {\n    bwRTreeNode_t *node;\n    struct bwLL *next;\n};\ntypedef struct bwZoomBuffer_t bwZoomBuffer_t;\nstruct bwZoomBuffer_t { //each individual entry takes 32 bytes\n    void *p;\n    uint32_t l, m;\n    struct bwZoomBuffer_t *next;\n};\n/// @endcond\n\n/*!\n * @brief This is only needed for writing bigWig files (and won't be created otherwise)\n * This should be removed from bigWig.h\n */\ntypedef struct {\n    uint64_t nBlocks; /**<The number of blocks written*/\n    uint32_t blockSize; /**<The maximum number of children*/\n    uint64_t nEntries; /**<The number of entries processed. This is used for the first contig and determining how the zoom levels are computed*/\n    uint64_t runningWidthSum; /**<The running sum of the entry widths for the first contig (again, used for the first contig and computing zoom levels)*/\n    uint32_t tid; /**<The current TID that's being processed*/\n    uint32_t start; /**<The start position of the block*/\n    uint32_t end; /**<The end position of the block*/\n    uint32_t span; /**<The span of each entry, if applicable*/\n    uint32_t step; /**<The step size, if applicable*/\n    uint8_t ltype; /**<The type of the last entry added*/\n    uint32_t l; /**<The current size of p. This and the type determine the number of items held*/\n    void *p; /**<A buffer of size hdr->bufSize*/\n    bwLL *firstIndexNode; /**<The first index node in the linked list*/\n    bwLL *currentIndexNode; /**<The last index node in a linked list*/\n    bwZoomBuffer_t **firstZoomBuffer; /**<The first node in a linked list of leaf nodes*/\n    bwZoomBuffer_t **lastZoomBuffer; /**<The last node in a linked list of leaf nodes*/\n    uint64_t *nNodes; /**<The number of leaf nodes per zoom level, useful for determining duplicate levels*/\n    uLongf compressPsz; /**<The size of the compression buffer*/\n    void *compressP; /**<A compressed buffer of size compressPsz*/\n} bwWriteBuffer_t;\n\n/*!\n * @brief A structure that holds everything needed to access a bigWig file.\n */\ntypedef struct {\n    URL_t *URL; /**<A pointer that can handle both local and remote files (including a buffer if needed).*/\n    bigWigHdr_t *hdr; /**<The file header.*/\n    chromList_t *cl; /**<A list of chromosome names (the order is the ID).*/\n    bwRTree_t *idx; /**<The index for the full dataset.*/\n    bwWriteBuffer_t *writeBuffer; /**<The buffer used for writing.*/\n    int isWrite; /**<0: Opened for reading, 1: Opened for writing.*/\n    int type; /**<0: bigWig, 1: bigBed.*/\n} bigWigFile_t;\n\n/*!\n * @brief Holds interval:value associations\n */\ntypedef struct {\n    uint32_t l; /**<Number of intervals held*/\n    uint32_t m; /**<Maximum number of values/intervals the struct can hold*/\n    uint32_t *start; /**<The start positions (0-based half open)*/\n    uint32_t *end; /**<The end positions (0-based half open)*/\n    float *value; /**<The value associated with each position*/\n} bwOverlappingIntervals_t;\n\n/*!\n * @brief Holds interval:str associations\n */\ntypedef struct {\n    uint32_t l; /**<Number of intervals held*/\n    uint32_t m; /**<Maximum number of values/intervals the struct can hold*/\n    uint32_t *start; /**<The start positions (0-based half open)*/\n    uint32_t *end; /**<The end positions (0-based half open)*/\n    char **str; /**<The strings associated with a given entry.*/\n} bbOverlappingEntries_t;\n\n/*!\n * @brief A structure to hold iterations\n * One of intervals and entries should be used to access records from bigWig or bigBed files, respectively.\n */\ntypedef struct {\n    bigWigFile_t *bw; /**<Pointer to the bigWig/bigBed file.*/\n    uint32_t tid; /**<The contig/chromosome ID.*/\n    uint32_t start; /**<Start position of the query interval.*/\n    uint32_t end; /**<End position of the query interval.*/\n    uint64_t offset; /**<Offset into the blocks.*/\n    uint32_t blocksPerIteration; /**<Number of blocks to use per iteration.*/\n    int withString; /**<For bigBed entries, whether to return the string with the entries.*/\n    void *blocks; /**<Overlapping blocks.*/\n    bwOverlappingIntervals_t *intervals; /**<Overlapping intervals (or NULL).*/\n    bbOverlappingEntries_t *entries; /**<Overlapping entries (or NULL).*/\n    void *data; /**<Points to either intervals or entries. If there are no further intervals/entries, then this is NULL. Use this to test for whether to continue iterating.*/\n} bwOverlapIterator_t;\n\n/*!\n * @brief Initializes curl and global variables. This *MUST* be called before other functions (at least if you want to connect to remote files).\n * For remote file, curl must be initialized and regions of a file read into an internal buffer. If the buffer is too small then an excessive number of connections will be made. If the buffer is too large than more data than required is fetched. 128KiB is likely sufficient for most needs.\n * @param bufSize The internal buffer size used for remote connection.\n * @see bwCleanup\n * @return 0 on success and 1 on error.\n */\nint bwInit(size_t bufSize);\n\n/*!\n * @brief The counterpart to bwInit, this cleans up curl.\n * @see bwInit\n */\nvoid bwCleanup(void);\n\n/*!\n * @brief Determine if a file is a bigWig file.\n * This function will quickly check either local or remote files to determine if they appear to be valid bigWig files. This can be determined by reading the first 4 bytes of the file.\n * @param fname The file name or URL (http, https, and ftp are supported)\n * @param callBack An optional user-supplied function. This is applied to remote connections so users can specify things like proxy and password information. See `test/testRemote` for an example.\n * @return 1 if the file appears to be bigWig, otherwise 0.\n */\nint bwIsBigWig(const char *fname, CURLcode (*callBack)(CURL*));\n\n/*!\n * @brief Determine is a file is a bigBed file.\n * This function will quickly check either local or remote files to determine if they appear to be valid bigWig files. This can be determined by reading the first 4 bytes of the file.\n * @param fname The file name or URL (http, https, and ftp are supported)\n * @param callBack An optional user-supplied function. This is applied to remote connections so users can specify things like proxy and password information. See `test/testRemote` for an example.\n * @return 1 if the file appears to be bigWig, otherwise 0.\n */\nint bbIsBigBed(const char *fname, CURLcode (*callBack)(CURL*));\n\n/*!\n * @brief Opens a local or remote bigWig file.\n * This will open a local or remote bigWig file. Writing of local bigWig files is also supported.\n * @param fname The file name or URL (http, https, and ftp are supported)\n * @param callBack An optional user-supplied function. This is applied to remote connections so users can specify things like proxy and password information. See `test/testRemote` for an example.\n * @param mode The mode, by default \"r\". Both local and remote files can be read, but only local files can be written. For files being written the callback function is ignored. If and only if the mode contains \"w\" will the file be opened for writing (in all other cases the file will be opened for reading.\n * @return A bigWigFile_t * on success and NULL on error.\n */\nbigWigFile_t *bwOpen(const char *fname, CURLcode (*callBack)(CURL*), const char* mode);\n\n/*!\n * @brief Opens a local or remote bigBed file.\n * This will open a local or remote bigBed file. Note that this file format can only be read and NOT written!\n * @param fname The file name or URL (http, https, and ftp are supported)\n * @param callBack An optional user-supplied function. This is applied to remote connections so users can specify things like proxy and password information. See `test/testRemote` for an example.\n * @return A bigWigFile_t * on success and NULL on error.\n */\nbigWigFile_t *bbOpen(const char *fname, CURLcode (*callBack)(CURL*));\n\n/*!\n * @brief Returns a string containing the SQL entry (or NULL).\n * The \"auto SQL\" field contains the names and value types of the entries in\n * each bigBed entry. If you need to parse a particular value out of each entry,\n * then you'll need to first parse this.\n * @param fp The file pointer to a valid bigWigFile_t\n * @return A char *, which you MUST free!\n */\nchar *bbGetSQL(bigWigFile_t *fp);\n\n/*!\n * @brief Closes a bigWigFile_t and frees up allocated memory\n * This closes both bigWig and bigBed files.\n * @param fp The file pointer.\n */\nvoid bwClose(bigWigFile_t *fp);\n\n/*******************************************************************************\n*\n* The following are in bwStats.c\n*\n*******************************************************************************/\n\n/*!\n * @brief Converts between chromosome name and ID\n *\n * @param fp A valid bigWigFile_t pointer\n * @param chrom A chromosome name\n * @return An ID, -1 will be returned on error (note that this is an unsigned value, so that's ~4 billion. bigWig/bigBed files can't store that many chromosomes anyway.\n */\nuint32_t bwGetTid(const bigWigFile_t *fp, const char *chrom);\n\n/*!\n * @brief Frees space allocated by `bwGetOverlappingIntervals`\n * @param o A valid `bwOverlappingIntervals_t` pointer.\n * @see bwGetOverlappingIntervals\n */\nvoid bwDestroyOverlappingIntervals(bwOverlappingIntervals_t *o);\n\n/*!\n * @brief Frees space allocated by `bbGetOverlappingEntries`\n * @param o A valid `bbOverlappingEntries_t` pointer.\n * @see bbGetOverlappingEntries\n */\nvoid bbDestroyOverlappingEntries(bbOverlappingEntries_t *o);\n\n/*!\n * @brief Return bigWig entries overlapping an interval.\n * Find all bigWig entries overlapping a range and returns them, including their associated values.\n * @param fp A valid bigWigFile_t pointer. This MUST be for a bigWig file!\n * @param chrom A valid chromosome name.\n * @param start The start position of the interval. This is 0-based half open, so 0 is the first base.\n * @param end The end position of the interval. Again, this is 0-based half open, so 100 will include the 100th base...which is at position 99.\n * @return NULL on error or no overlapping values, otherwise a `bwOverlappingIntervals_t *` holding the values and intervals.\n * @see bwOverlappingIntervals_t\n * @see bwDestroyOverlappingIntervals\n * @see bwGetValues\n */\nbwOverlappingIntervals_t *bwGetOverlappingIntervals(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end);\n\n/*!\n * @brief Return bigBed entries overlapping an interval.\n * Find all bigBed entries overlapping a range and returns them.\n * @param fp A valid bigWigFile_t pointer. This MUST be for a bigBed file!\n * @param chrom A valid chromosome name.\n * @param start The start position of the interval. This is 0-based half open, so 0 is the first base.\n * @param end The end position of the interval. Again, this is 0-based half open, so 100 will include the 100th base...which is at position 99.\n * @param withString If not 0, return the string associated with each entry in the output. If 0, there are no associated strings returned. This is useful if the only information needed are the locations of the entries, which require significantly less memory.\n * @return NULL on error or no overlapping values, otherwise a `bbOverlappingEntries_t *` holding the intervals and (optionally) the associated string.\n * @see bbOverlappingEntries_t\n * @see bbDestroyOverlappingEntries\n */\nbbOverlappingEntries_t *bbGetOverlappingEntries(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, int withString);\n\n/*!\n * @brief Creates an iterator over intervals in a bigWig file\n * Iterators can be traversed with `bwIteratorNext()` and destroyed with `bwIteratorDestroy()`.\n * Intervals are in the `intervals` member and `data` can be used to determine when to end iteration.\n * @param fp A valid bigWigFile_t pointer. This MUST be for a bigWig file!\n * @param chrom A valid chromosome name.\n * @param start The start position of the interval. This is 0-based half open, so 0 is the first base.\n * @param end The end position of the interval. Again, this is 0-based half open, so 100 will include the 100th base...which is at position 99.\n * @param blocksPerIteration The number of blocks (internal groupings of intervals in bigWig files) to return per iteration.\n * @return NULL on error, otherwise a bwOverlapIterator_t pointer\n * @see bwOverlapIterator_t\n * @see bwIteratorNext\n * @see bwIteratorDestroy\n */ \nbwOverlapIterator_t *bwOverlappingIntervalsIterator(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, uint32_t blocksPerIteration);\n\n/*!\n * @brief Creates an iterator over entries in a bigBed file\n * Iterators can be traversed with `bwIteratorNext()` and destroyed with `bwIteratorDestroy()`.\n * Entries are in the `entries` member and `data` can be used to determine when to end iteration.\n * @param fp A valid bigWigFile_t pointer. This MUST be for a bigBed file!\n * @param chrom A valid chromosome name.\n * @param start The start position of the interval. This is 0-based half open, so 0 is the first base.\n * @param end The end position of the interval. Again, this is 0-based half open, so 100 will include the 100th base...which is at position 99.\n * @param withString Whether the returned entries should include their associated strings.\n * @param blocksPerIteration The number of blocks (internal groupings of entries in bigBed files) to return per iteration.\n * @return NULL on error, otherwise a bwOverlapIterator_t pointer\n * @see bbGetOverlappingEntries\n * @see bwOverlapIterator_t\n * @see bwIteratorNext\n * @see bwIteratorDestroy\n */ \nbwOverlapIterator_t *bbOverlappingEntriesIterator(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, int withString, uint32_t blocksPerIteration);\n\n/*!\n * @brief Traverses to the entries/intervals in the next group of blocks.\n * @param iter A bwOverlapIterator_t pointer that is updated (or destroyed on error)\n * @return NULL on error, otherwise a bwOverlapIterator_t pointer with the intervals or entries from the next set of blocks.\n * @see bwOverlapIterator_t\n * @see bwIteratorDestroy\n */ \nbwOverlapIterator_t *bwIteratorNext(bwOverlapIterator_t *iter);\n\n/*!\n * @brief Destroys a bwOverlapIterator_t\n * @param iter The bwOverlapIterator_t that should be destroyed\n */\nvoid bwIteratorDestroy(bwOverlapIterator_t *iter);\n\n/*!\n * @brief Return all per-base bigWig values in a given interval.\n * Given an interval (e.g., chr1:0-100), return the value at each position in a bigWig file. Positions without associated values are suppressed by default, but may be returned if `includeNA` is not 0.\n * @param fp A valid bigWigFile_t pointer.\n * @param chrom A valid chromosome name.\n * @param start The start position of the interval. This is 0-based half open, so 0 is the first base.\n * @param end The end position of the interval. Again, this is 0-based half open, so 100 will include the 100th base...which is at position 99.\n * @param includeNA If not 0, report NA values as well (as NA).\n * @return NULL on error or no overlapping values, otherwise a `bwOverlappingIntervals_t *` holding the values and positions.\n * @see bwOverlappingIntervals_t\n * @see bwDestroyOverlappingIntervals\n * @see bwGetOverlappingIntervals\n */\nbwOverlappingIntervals_t *bwGetValues(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, int includeNA);\n\n/*!\n * @brief Determines per-interval bigWig statistics\n * Can determine mean/min/max/coverage/standard deviation of values in one or more intervals in a bigWig file. You can optionally give it an interval and ask for values from X number of sub-intervals.\n * @param fp The file from which to extract statistics.\n * @param chrom A valid chromosome name.\n * @param start The start position of the interval. This is 0-based half open, so 0 is the first base.\n * @param end The end position of the interval. Again, this is 0-based half open, so 100 will include the 100th base...which is at position 99.\n * @param nBins The number of bins within the interval to calculate statistics for.\n * @param type The type of statistic.\n * @see bwStatsType\n * @return A pointer to an array of double precission floating point values. Note that bigWig files only hold 32-bit values, so this is done to help prevent overflows.\n */\ndouble *bwStats(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, uint32_t nBins, enum bwStatsType type);\n\n/*!\n * @brief Determines per-interval bigWig statistics\n * Can determine mean/min/max/coverage/standard deviation of values in one or more intervals in a bigWig file. You can optionally give it an interval and ask for values from X number of sub-intervals. The difference with bwStats is that zoom levels are never used.\n * @param fp The file from which to extract statistics.\n * @param chrom A valid chromosome name.\n * @param start The start position of the interval. This is 0-based half open, so 0 is the first base.\n * @param end The end position of the interval. Again, this is 0-based half open, so 100 will include the 100th base...which is at position 99.\n * @param nBins The number of bins within the interval to calculate statistics for.\n * @param type The type of statistic.\n * @see bwStatsType\n * @return A pointer to an array of double precission floating point values. Note that bigWig files only hold 32-bit values, so this is done to help prevent overflows.\n*/\ndouble *bwStatsFromFull(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, uint32_t nBins, enum bwStatsType type);\n\n//Writer functions\n\n/*!\n * @brief Create a largely empty bigWig header\n * Every bigWig file has a header, this creates the template for one. It also takes care of space allocation in the output write buffer.\n * @param fp The bigWigFile_t* that you want to write to.\n * @param maxZooms The maximum number of zoom levels. If you specify 0 then there will be no zoom levels. A value <0 or > 65535 will result in a maximum of 10.\n * @return 0 on success.\n */\nint bwCreateHdr(bigWigFile_t *fp, int32_t maxZooms);\n\n/*!\n * @brief Take a list of chromosome names and lengths and return a pointer to a chromList_t\n * This MUST be run before `bwWriteHdr()`. Note that the input is NOT free()d!\n * @param chroms A list of chromosomes.\n * @param lengths The length of each chromosome.\n * @param n The number of chromosomes (thus, the length of `chroms` and `lengths`)\n * @return A pointer to a chromList_t or NULL on error.\n */\nchromList_t *bwCreateChromList(const char* const* chroms, const uint32_t *lengths, int64_t n);\n\n/*!\n * @brief Write a the header to a bigWig file.\n * You must have already opened the output file, created a header and a chromosome list.\n * @param bw The output bigWigFile_t pointer.\n * @see bwCreateHdr\n * @see bwCreateChromList\n */\nint bwWriteHdr(bigWigFile_t *bw);\n\n/*!\n * @brief Write a new block of bedGraph-like intervals to a bigWig file\n * Adds entries of the form:\n * chromosome\tstart\tend\tvalue\n * to the file. These will always be added in a new block, so you may have previously used a different storage type.\n * \n * In general it's more efficient to use the bwAppend* functions, but then you MUST know that the previously written block is of the same type. In other words, you can only use bwAppendIntervals() after bwAddIntervals() or a previous bwAppendIntervals().\n * @param fp The output file pointer.\n * @param chrom A list of chromosomes, of length `n`.\n * @param start A list of start positions of length`n`.\n * @param end A list of end positions of length`n`.\n * @param values A list of values of length`n`.\n * @param n The length of the aforementioned lists.\n * @return 0 on success and another value on error.\n * @see bwAppendIntervals\n */\nint bwAddIntervals(bigWigFile_t *fp, const char* const* chrom, const uint32_t *start, const uint32_t *end, const float *values, uint32_t n);\n\n/*!\n * @brief Append bedGraph-like intervals to a previous block of bedGraph-like intervals in a bigWig file.\n * If you have previously used bwAddIntervals() then this will append additional entries into the previous block (or start a new one if needed).\n * @param fp The output file pointer.\n * @param start A list of start positions of length`n`.\n * @param end A list of end positions of length`n`.\n * @param values A list of values of length`n`.\n * @param n The length of the aforementioned lists.\n * @return 0 on success and another value on error.\n * @warning Do NOT use this after `bwAddIntervalSpanSteps()`, `bwAppendIntervalSpanSteps()`, `bwAddIntervalSpanSteps()`, or `bwAppendIntervalSpanSteps()`.\n * @see bwAddIntervals\n */\nint bwAppendIntervals(bigWigFile_t *fp, const uint32_t *start, const uint32_t *end, const float *values, uint32_t n);\n\n/*!\n * @brief Add a new block of variable-step entries to a bigWig file\n * Adds entries for the form\n * chromosome\tstart\tvalue\n * to the file. Each block of such entries has an associated \"span\", so each value describes the region chromosome:start-(start+span)\n *\n * This will always start a new block of values.\n * @param fp The output file pointer.\n * @param chrom A list of chromosomes, of length `n`.\n * @param start A list of start positions of length`n`.\n * @param span The span of each entry (the must all be the same).\n * @param values A list of values of length`n`.\n * @param n The length of the aforementioned lists.\n * @return 0 on success and another value on error.\n * @see bwAppendIntervalSpans\n */\nint bwAddIntervalSpans(bigWigFile_t *fp, const char *chrom, const uint32_t *start, uint32_t span, const float *values, uint32_t n);\n\n/*!\n * @brief Append to a previous block of variable-step entries.\n * If you previously used `bwAddIntervalSpans()`, this will continue appending more values to the block(s) it created.\n * @param fp The output file pointer.\n * @param start A list of start positions of length`n`.\n * @param values A list of values of length`n`.\n * @param n The length of the aforementioned lists.\n * @return 0 on success and another value on error.\n * @warning Do NOT use this after `bwAddIntervals()`, `bwAppendIntervals()`, `bwAddIntervalSpanSteps()` or `bwAppendIntervalSpanSteps()`\n * @see bwAddIntervalSpans\n */\nint bwAppendIntervalSpans(bigWigFile_t *fp, const uint32_t *start, const float *values, uint32_t n);\n\n/*!\n * @brief Add a new block of fixed-step entries to a bigWig file\n * Adds entries for the form\n * value\n * to the file. Each block of such entries has an associated \"span\", \"step\", chromosome and start position. See the wiggle format for more details.\n *\n * This will always start a new block of values.\n * @param fp The output file pointer.\n * @param chrom The chromosome that the entries describe.\n * @param start The starting position of the block of entries.\n * @param span The span of each entry (i.e., the number of bases it describes).\n * @param step The step between entry start positions.\n * @param values A list of values of length`n`.\n * @param n The length of the aforementioned lists.\n * @return 0 on success and another value on error.\n * @see bwAddIntervalSpanSteps\n */\nint bwAddIntervalSpanSteps(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t span, uint32_t step, const float *values, uint32_t n);\n\n/*!\n * @brief Append to a previous block of fixed-step entries.\n * If you previously used `bwAddIntervalSpanSteps()`, this will continue appending more values to the block(s) it created.\n * @param fp The output file pointer.\n * @param values A list of values of length`n`.\n * @param n The length of the aforementioned lists.\n * @return 0 on success and another value on error.\n * @warning Do NOT use this after `bwAddIntervals()`, `bwAppendIntervals()`, `bwAddIntervalSpans()` or `bwAppendIntervalSpans()`\n * @see bwAddIntervalSpanSteps\n */\nint bwAppendIntervalSpanSteps(bigWigFile_t *fp, const float *values, uint32_t n);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // LIBBIGWIG_H\n"
  },
  {
    "path": "libBigWig/bigWigIO.h",
    "content": "#ifndef LIBBIGWIG_IO_H\n#define LIBBIGWIG_IO_H\n\n#ifndef NOCURL\n#include <curl/curl.h>\n#else\n#include <stdio.h>\n#ifndef CURLTYPE_DEFINED\n#define CURLTYPE_DEFINED\ntypedef int CURLcode;\ntypedef void CURL;\n#endif\n#define CURLE_OK 0\n#define CURLE_FAILED_INIT 1\n#endif\n/*! \\file bigWigIO.h\n * These are (typically internal) IO functions, so there's generally no need for you to directly use them!\n */\n\n/*!\n * The size of the buffer used for remote files.\n */\nextern size_t GLOBAL_DEFAULTBUFFERSIZE;\n\n/*!\n * The enumerated values that indicate the connection type used to access a file.\n */\nenum bigWigFile_type_enum {\n    BWG_FILE = 0,\n    BWG_HTTP = 1,\n    BWG_HTTPS = 2,\n    BWG_FTP = 3\n};\n\n/*!\n * @brief This structure holds the file pointers and buffers needed for raw access to local and remote files.\n */\ntypedef struct {\n    union {\n#ifndef NOCURL\n        CURL *curl; /**<The CURL * file pointer for remote files.*/\n#endif\n        FILE *fp; /**<The FILE * file pointer for local files.**/\n    } x; /**<A union holding curl and fp.*/\n    void *memBuf; /**<A void * pointing to memory of size bufSize.*/\n    size_t filePos; /**<Current position inside the file.*/\n    size_t bufPos; /**<Curent position inside the buffer.*/\n    size_t bufSize; /**<The size of the buffer.*/\n    size_t bufLen; /**<The actual size of the buffer used.*/\n    enum bigWigFile_type_enum type; /**<The connection type*/\n    int isCompressed; /**<1 if the file is compressed, otherwise 0*/\n    const char *fname; /**<Only needed for remote connections. The original URL/filename requested, since we need to make multiple connections.*/\n} URL_t;\n\n/*!\n *  @brief Reads data into the given buffer.\n *\n *  This function will store bufSize data into buf for both local and remote files. For remote files an internal buffer is used to store a (typically larger) segment of the remote file.\n *\n *  @param URL A URL_t * pointing to a valid opened file or remote URL.\n *  @param buf The buffer in memory that you would like filled. It must be able to hold bufSize bytes!\n *  @param bufSize The number of bytes to transfer to buf.\n *\n *  @return Returns the number of bytes stored in buf, which should be bufSize on success and something else on error.\n *\n *  @warning Note that on error, URL for remote files is left in an unusable state. You can get around this by running urlSeek() to a position outside of the range held by the internal buffer.\n */\nsize_t urlRead(URL_t *URL, void *buf, size_t bufSize);\n\n/*!\n *  @brief Seeks to a given position in a local or remote file.\n * \n *  For local files, this will set the file position indicator for the file pointer to the desired position. For remote files, it sets the position to start downloading data for the next urlRead(). Note that for remote files that running urlSeek() with a pos within the current buffer will simply modify the internal offset.\n *\n *  @param URL A URL_t * pointing to a valid opened file or remote URL.\n *  @param pos The position to seek to.\n *\n *  @return CURLE_OK on success and a different CURLE_XXX on error. For local files, the error return value is always CURLE_FAILED_INIT\n */\nCURLcode urlSeek(URL_t *URL, size_t pos);\n\n/*!\n *  @brief Open a local or remote file\n *\n *  Opens a local or remote file. Currently, http, https, and ftp are the only supported protocols and the URL must then begin with \"http://\", \"https://\", or \"ftp://\" as appropriate.\n *\n *  For remote files, an internal buffer is used to hold file contents, to avoid downloading entire files before starting. The size of this buffer and various variable related to connection timeout are set with bwInit().\n *\n *  Note that you **must** run urlClose() on this when finished. However, you would typically just use bwOpen() rather than directly calling this function.\n *\n * @param fname The file name or URL to open.\n * @param callBack An optional user-supplied function. This is applied to remote connections so users can specify things like proxy and password information.\n * @param mode \"r\", \"w\" or NULL. If and only if the mode contains the character \"w\" will the file be opened for writing.\n *\n *  @return A URL_t * or NULL on error.\n */\nURL_t *urlOpen(const char *fname, CURLcode (*callBack)(CURL*), const char* mode);\n\n/*!\n *  @brief Close a local/remote file\n *\n *  This will perform the cleanup required on a URL_t*, releasing memory as needed.\n *\n *  @param URL A URL_t * pointing to a valid opened file or remote URL.\n *\n *  @warning URL will no longer point to a valid location in memory!\n */\nvoid urlClose(URL_t *URL);\n\n#endif // LIBBIGWIG_IO_H\n"
  },
  {
    "path": "libBigWig/bwCommon.h",
    "content": "/*! \\file bwCommon.h\n *\n * You have no reason to use these functions. They may change without warning because there's no reason for them to be used outside of libBigWig's internals.\n *\n * These are structures and functions from a variety of files that are used across files internally but don't need to be see by libBigWig users.\n */\n\n/*!\n * @brief Like fsetpos, but for local or remote bigWig files.\n * This will set the file position indicator to the specified point. For local files this literally is `fsetpos`, while for remote files it fills a memory buffer with data starting at the desired position.\n * @param fp A valid opened bigWigFile_t.\n * @param pos The position within the file to seek to.\n * @return 0 on success and -1 on error.\n */\nint bwSetPos(bigWigFile_t *fp, size_t pos);\n\n/*!\n * @brief A local/remote version of `fread`.\n * Reads data from either local or remote bigWig files.\n * @param data An allocated memory block big enough to hold the data.\n * @param sz The size of each member that should be copied.\n * @param nmemb The number of members to copy.\n * @param fp The bigWigFile_t * from which to copy the data.\n * @see bwSetPos\n * @return For nmemb==1, the size of the copied data. For nmemb>1, the number of members fully copied (this is equivalent to `fread`).\n */\nsize_t bwRead(void *data, size_t sz, size_t nmemb, bigWigFile_t *fp);\n\n/*!\n * @brief Determine what the file position indicator say.\n * This is equivalent to `ftell` for local or remote files.\n * @param fp The file.\n * @return The position in the file.\n */\nlong bwTell(bigWigFile_t *fp);\n\n/*!\n * @brief Reads a data index (either full data or a zoom level) from a bigWig file.\n * There is little reason for end users to use this function. This must be freed with `bwDestroyIndex`\n * @param fp A valid bigWigFile_t pointer\n * @param offset The file offset where the index begins\n * @return A bwRTree_t pointer or NULL on error.\n */\nbwRTree_t *bwReadIndex(bigWigFile_t *fp, uint64_t offset);\n\n/*!\n * @brief Destroy an bwRTreeNode_t and all of its children.\n * @param node The node to destroy.\n */\nvoid bwDestroyIndexNode(bwRTreeNode_t *node);\n\n/*!\n * @brief Frees space allocated by `bwReadIndex`\n * There is generally little reason to use this, since end users should typically not need to run `bwReadIndex` themselves.\n * @param idx A bwRTree_t pointer allocated by `bwReadIndex`.\n */\nvoid bwDestroyIndex(bwRTree_t *idx);\n\n/// @cond SKIP\nbwOverlapBlock_t *walkRTreeNodes(bigWigFile_t *bw, bwRTreeNode_t *root, uint32_t tid, uint32_t start, uint32_t end);\nvoid destroyBWOverlapBlock(bwOverlapBlock_t *b);\n/// @endcond\n\n/*!\n * @brief Finishes what's needed to write a bigWigFile\n * Flushes the buffer, converts the index linked list to a tree, writes that to disk, handles zoom level stuff, writes magic at the end\n * @param fp A valid bigWigFile_t pointer\n * @return 0 on success\n */\nint bwFinalize(bigWigFile_t *fp);\n\n/// @cond SKIP\nchar *bwStrdup(const char *s);\n/// @endcond\n"
  },
  {
    "path": "libBigWig/bwRead.c",
    "content": "#include \"bigWig.h\"\n#include \"bwCommon.h\"\n#include <stdlib.h>\n#include <math.h>\n#include <string.h>\n#include <stdio.h>\n\nstatic uint64_t readChromBlock(bigWigFile_t *bw, chromList_t *cl, uint32_t keySize);\n\n//Return the position in the file\nlong bwTell(bigWigFile_t *fp) {\n    if(fp->URL->type == BWG_FILE) return ftell(fp->URL->x.fp);\n    return (long) (fp->URL->filePos + fp->URL->bufPos);\n}\n\n//Seek to a given position, always from the beginning of the file\n//Return 0 on success and -1 on error\n//To do, use the return code of urlSeek() in a more useful way.\nint bwSetPos(bigWigFile_t *fp, size_t pos) {\n    CURLcode rv = urlSeek(fp->URL, pos);\n    if(rv == CURLE_OK) return 0;\n    return -1;\n}\n\n//returns the number of full members read (nmemb on success, something less on error)\nsize_t bwRead(void *data, size_t sz, size_t nmemb, bigWigFile_t *fp) {\n    size_t i, rv;\n    for(i=0; i<nmemb; i++) {\n        rv = urlRead(fp->URL, data+i*sz, sz);\n        if(rv != sz) return i;\n    }\n    return nmemb;\n}\n\n//Initializes curl and sets global variables\n//Returns 0 on success and 1 on error\n//This should be called only once and bwCleanup() must be called when finished.\nint bwInit(size_t defaultBufSize) {\n    //set the buffer size, number of iterations, sleep time between iterations, etc.\n    GLOBAL_DEFAULTBUFFERSIZE = defaultBufSize;\n\n    //call curl_global_init()\n#ifndef NOCURL\n    CURLcode rv;\n    rv = curl_global_init(CURL_GLOBAL_ALL);\n    if(rv != CURLE_OK) return 1;\n#endif\n    return 0;\n}\n\n//This should be called before quiting, to release memory acquired by curl\nvoid bwCleanup() {\n#ifndef NOCURL\n    curl_global_cleanup();\n#endif\n}\n\nstatic bwZoomHdr_t *bwReadZoomHdrs(bigWigFile_t *bw) {\n    if(bw->isWrite) return NULL;\n    uint16_t i;\n    bwZoomHdr_t *zhdr = malloc(sizeof(bwZoomHdr_t));\n    if(!zhdr) return NULL;\n    uint32_t *level = malloc(bw->hdr->nLevels * sizeof(uint64_t));\n    if(!level) {\n        free(zhdr);\n        return NULL;\n    }\n    uint32_t padding = 0;\n    uint64_t *dataOffset = malloc(sizeof(uint64_t) * bw->hdr->nLevels);\n    if(!dataOffset) {\n        free(zhdr);\n        free(level);\n        return NULL;\n    }\n    uint64_t *indexOffset = malloc(sizeof(uint64_t) * bw->hdr->nLevels);\n    if(!indexOffset) {\n        free(zhdr);\n        free(level);\n        free(dataOffset);\n        return NULL;\n    }\n\n    for(i=0; i<bw->hdr->nLevels; i++) {\n        if(bwRead((void*) &(level[i]), sizeof(uint32_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &padding, sizeof(uint32_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &(dataOffset[i]), sizeof(uint64_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &(indexOffset[i]), sizeof(uint64_t), 1, bw) != 1) goto error;\n    }\n\n    zhdr->level = level;\n    zhdr->dataOffset = dataOffset;\n    zhdr->indexOffset = indexOffset;\n    zhdr->idx = calloc(bw->hdr->nLevels, sizeof(bwRTree_t*));\n    if(!zhdr->idx) goto error;\n\n    return zhdr;\n\nerror:\n    for(i=0; i<bw->hdr->nLevels; i++) {\n        if(zhdr->idx[i]) bwDestroyIndex(zhdr->idx[i]);\n    }\n    free(zhdr);\n    free(level);\n    free(dataOffset);\n    free(indexOffset);\n    return NULL;\n}\n\nstatic void bwHdrDestroy(bigWigHdr_t *hdr) {\n    int i;\n    if(hdr->zoomHdrs) {\n        free(hdr->zoomHdrs->level);\n        free(hdr->zoomHdrs->dataOffset);\n        free(hdr->zoomHdrs->indexOffset);\n        for(i=0; i<hdr->nLevels; i++) {\n            if(hdr->zoomHdrs->idx[i]) bwDestroyIndex(hdr->zoomHdrs->idx[i]);\n        }\n        free(hdr->zoomHdrs->idx);\n        free(hdr->zoomHdrs);\n    }\n    free(hdr);\n}\n\nstatic void bwHdrRead(bigWigFile_t *bw) {\n    uint32_t magic;\n    if(bw->isWrite) return;\n    bw->hdr = calloc(1, sizeof(bigWigHdr_t));\n    if(!bw->hdr) return;\n\n    if(bwRead((void*) &magic, sizeof(uint32_t), 1, bw) != 1) goto error; //0x0\n    if(magic != BIGWIG_MAGIC && magic != BIGBED_MAGIC) goto error;\n\n    if(bwRead((void*) &(bw->hdr->version), sizeof(uint16_t), 1, bw) != 1) goto error; //0x4\n    if(bwRead((void*) &(bw->hdr->nLevels), sizeof(uint16_t), 1, bw) != 1) goto error; //0x6\n    if(bwRead((void*) &(bw->hdr->ctOffset), sizeof(uint64_t), 1, bw) != 1) goto error; //0x8\n    if(bwRead((void*) &(bw->hdr->dataOffset), sizeof(uint64_t), 1, bw) != 1) goto error; //0x10\n    if(bwRead((void*) &(bw->hdr->indexOffset), sizeof(uint64_t), 1, bw) != 1) goto error; //0x18\n    if(bwRead((void*) &(bw->hdr->fieldCount), sizeof(uint16_t), 1, bw) != 1) goto error; //0x20\n    if(bwRead((void*) &(bw->hdr->definedFieldCount), sizeof(uint16_t), 1, bw) != 1) goto error; //0x22\n    if(bwRead((void*) &(bw->hdr->sqlOffset), sizeof(uint64_t), 1, bw) != 1) goto error; //0x24\n    if(bwRead((void*) &(bw->hdr->summaryOffset), sizeof(uint64_t), 1, bw) != 1) goto error; //0x2c\n    if(bwRead((void*) &(bw->hdr->bufSize), sizeof(uint32_t), 1, bw) != 1) goto error; //0x34\n    if(bwRead((void*) &(bw->hdr->extensionOffset), sizeof(uint64_t), 1, bw) != 1) goto error; //0x38\n\n    //zoom headers\n    if(bw->hdr->nLevels) {\n        if(!(bw->hdr->zoomHdrs = bwReadZoomHdrs(bw))) goto error;\n    }\n\n    //File summary information\n    if(bw->hdr->summaryOffset) {\n        if(urlSeek(bw->URL, bw->hdr->summaryOffset) != CURLE_OK) goto error;\n        if(bwRead((void*) &(bw->hdr->nBasesCovered), sizeof(uint64_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &(bw->hdr->minVal), sizeof(uint64_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &(bw->hdr->maxVal), sizeof(uint64_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &(bw->hdr->sumData), sizeof(uint64_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &(bw->hdr->sumSquared), sizeof(uint64_t), 1, bw) != 1) goto error;\n    }\n\n    //In case of uncompressed remote files, let the IO functions know to request larger chunks\n    bw->URL->isCompressed = (bw->hdr->bufSize > 0)?1:0;\n\n    return;\n\nerror:\n    bwHdrDestroy(bw->hdr);\n    fprintf(stderr, \"[bwHdrRead] There was an error while reading in the header!\\n\");\n    bw->hdr = NULL;\n}\n\nstatic void destroyChromList(chromList_t *cl) {\n    uint32_t i;\n    if(!cl) return;\n    if(cl->nKeys && cl->chrom) {\n        for(i=0; i<cl->nKeys; i++) {\n            if(cl->chrom[i]) free(cl->chrom[i]);\n        }\n    }\n    if(cl->chrom) free(cl->chrom);\n    if(cl->len) free(cl->len);\n    free(cl);\n}\n\nstatic uint64_t readChromLeaf(bigWigFile_t *bw, chromList_t *cl, uint32_t valueSize) {\n    uint16_t nVals, i;\n    uint32_t idx;\n    char *chrom = NULL;\n\n    if(bwRead((void*) &nVals, sizeof(uint16_t), 1, bw) != 1) return -1;\n    chrom = calloc(valueSize+1, sizeof(char));\n    if(!chrom) return -1;\n\n    for(i=0; i<nVals; i++) {\n        if(bwRead((void*) chrom, sizeof(char), valueSize, bw) != valueSize) goto error;\n        if(bwRead((void*) &idx, sizeof(uint32_t), 1, bw) != 1) goto error;\n        if(bwRead((void*) &(cl->len[idx]), sizeof(uint32_t), 1, bw) != 1) goto error;\n        cl->chrom[idx] = bwStrdup(chrom);\n        if(!(cl->chrom[idx])) goto error;\n    }\n\n    free(chrom);\n    return nVals;\n\nerror:\n    free(chrom);\n    return -1;\n}\n\nstatic uint64_t readChromNonLeaf(bigWigFile_t *bw, chromList_t *cl, uint32_t keySize) {\n    uint64_t offset , rv = 0, previous;\n    uint16_t nVals, i;\n\n    if(bwRead((void*) &nVals, sizeof(uint16_t), 1, bw) != 1) return -1;\n\n    previous = bwTell(bw) + keySize;\n    for(i=0; i<nVals; i++) {\n        if(bwSetPos(bw, previous)) return -1;\n        if(bwRead((void*) &offset, sizeof(uint64_t), 1, bw) != 1) return -1;\n        if(bwSetPos(bw, offset)) return -1;\n        rv += readChromBlock(bw, cl, keySize);\n        previous += 8 + keySize;\n    }\n\n    return rv;\n}\n\nstatic uint64_t readChromBlock(bigWigFile_t *bw, chromList_t *cl, uint32_t keySize) {\n    uint8_t isLeaf, padding;\n\n    if(bwRead((void*) &isLeaf, sizeof(uint8_t), 1, bw) != 1) return -1;\n    if(bwRead((void*) &padding, sizeof(uint8_t), 1, bw) != 1) return -1;\n\n    if(isLeaf) {\n        return readChromLeaf(bw, cl, keySize);\n    } else { //I've never actually observed one of these, which is good since they're pointless\n        return readChromNonLeaf(bw, cl, keySize);\n    }\n}\n\nstatic chromList_t *bwReadChromList(bigWigFile_t *bw) {\n    chromList_t *cl = NULL;\n    uint32_t magic, keySize, valueSize, itemsPerBlock;\n    uint64_t rv, itemCount;\n    if(bw->isWrite) return NULL;\n    if(bwSetPos(bw, bw->hdr->ctOffset)) return NULL;\n\n    cl = calloc(1, sizeof(chromList_t));\n    if(!cl) return NULL;\n\n    if(bwRead((void*) &magic, sizeof(uint32_t), 1, bw) != 1) goto error;\n    if(magic != CIRTREE_MAGIC) goto error;\n\n    if(bwRead((void*) &itemsPerBlock, sizeof(uint32_t), 1, bw) != 1) goto error;\n    if(bwRead((void*) &keySize, sizeof(uint32_t), 1, bw) != 1) goto error;\n    if(bwRead((void*) &valueSize, sizeof(uint32_t), 1, bw) != 1) goto error;\n    if(bwRead((void*) &itemCount, sizeof(uint64_t), 1, bw) != 1) goto error;\n\n    cl->nKeys = itemCount;\n    cl->chrom = calloc(itemCount, sizeof(char*));\n    cl->len = calloc(itemCount, sizeof(uint32_t));\n    if(!cl->chrom) goto error;\n    if(!cl->len) goto error;\n\n    if(bwRead((void*) &magic, sizeof(uint32_t), 1, bw) != 1) goto error;\n    if(bwRead((void*) &magic, sizeof(uint32_t), 1, bw) != 1) goto error;\n\n    //Read in the blocks\n    rv = readChromBlock(bw, cl, keySize);\n    if(rv == (uint64_t) -1) goto error;\n    if(rv != itemCount) goto error;\n\n    return cl;\n\nerror:\n    destroyChromList(cl);\n    return NULL;\n}\n\n//This is here mostly for convenience\nstatic void bwDestroyWriteBuffer(bwWriteBuffer_t *wb) {\n    if(wb->p) free(wb->p);\n    if(wb->compressP) free(wb->compressP);\n    if(wb->firstZoomBuffer) free(wb->firstZoomBuffer);\n    if(wb->lastZoomBuffer) free(wb->lastZoomBuffer);\n    if(wb->nNodes) free(wb->nNodes);\n    free(wb);\n}\n\nvoid bwClose(bigWigFile_t *fp) {\n    if(!fp) return;\n    if(bwFinalize(fp)) {\n        fprintf(stderr, \"[bwClose] There was an error while finishing writing a bigWig file! The output is likely truncated.\\n\");\n    }\n    if(fp->URL) urlClose(fp->URL);\n    if(fp->hdr) bwHdrDestroy(fp->hdr);\n    if(fp->cl) destroyChromList(fp->cl);\n    if(fp->idx) bwDestroyIndex(fp->idx);\n    if(fp->writeBuffer) bwDestroyWriteBuffer(fp->writeBuffer);\n    free(fp);\n}\n\nint bwIsBigWig(const char *fname, CURLcode (*callBack) (CURL*)) {\n    uint32_t magic = 0;\n    URL_t *URL = NULL;\n\n    URL = urlOpen(fname, *callBack, NULL);\n\n    if(!URL) return 0;\n    if(urlRead(URL, (void*) &magic, sizeof(uint32_t)) != sizeof(uint32_t)) magic = 0;\n    urlClose(URL);\n    if(magic == BIGWIG_MAGIC) return 1;\n    return 0;\n}\n\nchar *bbGetSQL(bigWigFile_t *fp) {\n    char *o = NULL;\n    uint64_t len;\n    if(!fp->hdr->sqlOffset) return NULL;\n    len = fp->hdr->summaryOffset - fp->hdr->sqlOffset; //This includes the NULL terminator\n    o = malloc(sizeof(char) * len);\n    if(!o) goto error;\n    if(bwSetPos(fp, fp->hdr->sqlOffset)) goto error;\n    if(bwRead((void*) o, len, 1, fp) != 1) goto error;\n    return o;\n\nerror:\n    if(o) free(o);\n    printf(\"Got an error in bbGetSQL!\\n\");\n    return NULL;\n}\n\nint bbIsBigBed(const char *fname, CURLcode (*callBack) (CURL*)) {\n    uint32_t magic = 0;\n    URL_t *URL = NULL;\n\n    URL = urlOpen(fname, *callBack, NULL);\n\n    if(!URL) return 0;\n    if(urlRead(URL, (void*) &magic, sizeof(uint32_t)) != sizeof(uint32_t)) magic = 0;\n    urlClose(URL);\n    if(magic == BIGBED_MAGIC) return 1;\n    return 0;\n}\n\nbigWigFile_t *bwOpen(const char *fname, CURLcode (*callBack) (CURL*), const char *mode) {\n    bigWigFile_t *bwg = calloc(1, sizeof(bigWigFile_t));\n    if(!bwg) {\n        fprintf(stderr, \"[bwOpen] Couldn't allocate space to create the output object!\\n\");\n        return NULL;\n    }\n    if((!mode) || (strchr(mode, 'w') == NULL)) {\n        bwg->isWrite = 0;\n        bwg->URL = urlOpen(fname, *callBack, NULL);\n        if(!bwg->URL) {\n            fprintf(stderr, \"[bwOpen] urlOpen is NULL!\\n\");\n            goto error;\n        }\n\n        //Attempt to read in the fixed header\n        bwHdrRead(bwg);\n        if(!bwg->hdr) {\n            fprintf(stderr, \"[bwOpen] bwg->hdr is NULL!\\n\");\n            goto error;\n        }\n\n        //Read in the chromosome list\n        bwg->cl = bwReadChromList(bwg);\n        if(!bwg->cl) {\n            fprintf(stderr, \"[bwOpen] bwg->cl is NULL (%s)!\\n\", fname);\n            goto error;\n        }\n\n        //Read in the index\n        if(bwg->hdr->indexOffset) {\n            bwg->idx = bwReadIndex(bwg, 0);\n            if(!bwg->idx) {\n                fprintf(stderr, \"[bwOpen] bwg->idx is NULL bwg->hdr->dataOffset 0x%\"PRIx64\"!\\n\", bwg->hdr->dataOffset);\n                goto error;\n            }\n        }\n    } else {\n        bwg->isWrite = 1;\n        bwg->URL = urlOpen(fname, NULL, \"w+\");\n        if(!bwg->URL) goto error;\n        bwg->writeBuffer = calloc(1,sizeof(bwWriteBuffer_t));\n        if(!bwg->writeBuffer) goto error;\n        bwg->writeBuffer->l = 24;\n    }\n\n    return bwg;\n\nerror:\n    bwClose(bwg);\n    return NULL;\n}\n\nbigWigFile_t *bbOpen(const char *fname, CURLcode (*callBack) (CURL*)) {\n    bigWigFile_t *bb = calloc(1, sizeof(bigWigFile_t));\n    if(!bb) {\n        fprintf(stderr, \"[bbOpen] Couldn't allocate space to create the output object!\\n\");\n        return NULL;\n    }\n\n    //Set the type to 1 for bigBed\n    bb->type = 1;\n\n    bb->URL = urlOpen(fname, *callBack, NULL);\n    if(!bb->URL) goto error;\n\n    //Attempt to read in the fixed header\n    bwHdrRead(bb);\n    if(!bb->hdr) goto error;\n\n    //Read in the chromosome list\n    bb->cl = bwReadChromList(bb);\n    if(!bb->cl) goto error;\n\n    //Read in the index\n    bb->idx = bwReadIndex(bb, 0);\n    if(!bb->idx) goto error;\n\n    return bb;\n\nerror:\n    bwClose(bb);\n    return NULL;\n}\n\n\n//Implementation taken from musl:\n//https://git.musl-libc.org/cgit/musl/tree/src/string/strdup.c\n//License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT\nchar* bwStrdup(const char *s) {\n\tsize_t l = strlen(s);\n\tchar *d = malloc(l+1);\n\tif (!d) return NULL;\n\treturn memcpy(d, s, l+1);\n}\n"
  },
  {
    "path": "libBigWig/bwStats.c",
    "content": "#include \"bigWig.h\"\n#include \"bwCommon.h\"\n#include <errno.h>\n#include <stdlib.h>\n#include <zlib.h>\n#include <math.h>\n#include <string.h>\n\n//Returns -1 if there are no applicable levels, otherwise an integer indicating the most appropriate level.\n//Like Kent's library, this divides the desired bin size by 2 to minimize the effect of blocks overlapping multiple bins\nstatic int32_t determineZoomLevel(const bigWigFile_t *fp, int basesPerBin) {\n    int32_t out = -1;\n    int64_t diff;\n    uint32_t bestDiff = -1;\n    uint16_t i;\n\n    basesPerBin/=2;\n    for(i=0; i<fp->hdr->nLevels; i++) {\n        diff = basesPerBin - (int64_t) fp->hdr->zoomHdrs->level[i];\n        if(diff >= 0 && diff < bestDiff) {\n            bestDiff = diff;\n            out = i;\n        }\n    }\n    return out;\n}\n\n/// @cond SKIP\nstruct val_t {\n    uint32_t nBases;\n    float min, max, sum, sumsq;\n    double scalar;\n};\n\nstruct vals_t {\n    uint32_t n;\n    struct val_t **vals;\n};\n/// @endcond\n\nvoid destroyVals_t(struct vals_t *v) {\n    uint32_t i;\n    if(!v) return;\n    for(i=0; i<v->n; i++) free(v->vals[i]);\n    if(v->vals) free(v->vals);\n    free(v);\n}\n\n//Determine the base-pair overlap between an interval and a block\ndouble getScalar(uint32_t i_start, uint32_t i_end, uint32_t b_start, uint32_t b_end) {\n    double rv = 0.0;\n    if(b_start <= i_start) {\n        if(b_end > i_start) rv = ((double)(b_end - i_start))/(b_end-b_start);\n    } else if(b_start < i_end) {\n        if(b_end < i_end) rv = ((double)(b_end - b_start))/(b_end-b_start);\n        else rv = ((double)(i_end - b_start))/(b_end-b_start);\n    }\n\n    return rv;\n}\n\n//Returns NULL on error\nstatic struct vals_t *getVals(bigWigFile_t *fp, bwOverlapBlock_t *o, int i, uint32_t tid, uint32_t start, uint32_t end) {\n    void *buf = NULL, *compBuf = NULL;\n    uLongf sz = fp->hdr->bufSize;\n    int compressed = 0, rv;\n    uint32_t *p, vtid, vstart, vend;\n    struct vals_t *vals = NULL;\n    struct val_t *v = NULL;\n\n    if(sz) {\n        compressed = 1;\n        buf = malloc(sz);\n    }\n    sz = 0; //This is now the size of the compressed buffer\n\n    if(bwSetPos(fp, o->offset[i])) goto error;\n\n    vals = calloc(1,sizeof(struct vals_t));\n    if(!vals) goto error;\n\n    v = malloc(sizeof(struct val_t));\n    if(!v) goto error;\n\n    if(sz < o->size[i]) compBuf = malloc(o->size[i]);\n    if(!compBuf) goto error;\n\n    if(bwRead(compBuf, o->size[i], 1, fp) != 1) goto error;\n    if(compressed) {\n        sz = fp->hdr->bufSize;\n        rv = uncompress(buf, &sz, compBuf, o->size[i]);\n        if(rv != Z_OK) goto error;\n    } else {\n        buf = compBuf;\n        sz = o->size[i];\n    }\n\n    p = buf;\n    while(((uLongf) ((char*)p - (char*)buf)) < sz) {\n        vtid = p[0];\n        vstart = p[1];\n        vend = p[2];\n        v->nBases = p[3];\n        v->min = ((float*) p)[4];\n        v->max = ((float*) p)[5];\n        v->sum = ((float*) p)[6];\n        v->sumsq = ((float*) p)[7];\n        v->scalar = getScalar(start, end, vstart, vend);\n\n        if(tid == vtid) {\n            if((start <= vstart && end > vstart) || (start < vend && start >= vstart)) {\n                vals->vals = realloc(vals->vals, sizeof(struct val_t*)*(vals->n+1));\n                if(!vals->vals) goto error;\n                vals->vals[vals->n++] = v;\n                v = malloc(sizeof(struct val_t));\n                if(!v) goto error;\n            }\n            if(vstart > end) break;\n        } else if(vtid > tid) {\n            break;\n        }\n        p+=8;\n    }\n\n    free(v);\n    free(buf);\n    if(compressed) free(compBuf);\n    return vals;\n\nerror:\n    if(buf) free(buf);\n    if(compBuf && compressed) free(compBuf);\n    if(v) free(v);\n    destroyVals_t(vals);\n    return NULL;\n}\n\n//On error, errno is set to ENOMEM and NaN is returned (though NaN can be returned normally)\nstatic double blockMean(bigWigFile_t *fp, bwOverlapBlock_t *blocks, uint32_t tid, uint32_t start, uint32_t end) {\n    uint32_t i, j;\n    double output = 0.0, coverage = 0.0;\n    struct vals_t *v = NULL;\n\n    if(!blocks->n) return strtod(\"NaN\", NULL);\n\n    //Iterate over the blocks\n    for(i=0; i<blocks->n; i++) {\n        v = getVals(fp, blocks, i, tid, start, end);\n        if(!v) goto error;\n        for(j=0; j<v->n; j++) {\n            output += v->vals[j]->sum * v->vals[j]->scalar;\n            coverage += v->vals[j]->nBases * v->vals[j]->scalar;\n        }\n        destroyVals_t(v);\n    }\n\n\n    if(!coverage) return strtod(\"NaN\", NULL);\n\n    return output/coverage;\n\nerror:\n    if(v) free(v);\n    errno = ENOMEM;\n    return strtod(\"NaN\", NULL);\n}\n\nstatic double intMean(bwOverlappingIntervals_t* ints, uint32_t start, uint32_t end) {\n    double sum = 0.0;\n    uint32_t nBases = 0, i, start_use, end_use;\n\n    if(!ints->l) return strtod(\"NaN\", NULL);\n\n    for(i=0; i<ints->l; i++) {\n        start_use = ints->start[i];\n        end_use = ints->end[i];\n        if(ints->start[i] < start) start_use = start;\n        if(ints->end[i] > end) end_use = end;\n        nBases += end_use-start_use;\n        sum += (end_use-start_use)*((double) ints->value[i]);\n    }\n\n    return sum/nBases;\n}\n\n//Does UCSC compensate for partial block/range overlap?\nstatic double blockDev(bigWigFile_t *fp, bwOverlapBlock_t *blocks, uint32_t tid, uint32_t start, uint32_t end) {\n    uint32_t i, j;\n    double mean = 0.0, ssq = 0.0, coverage = 0.0, diff;\n    struct vals_t *v = NULL;\n\n    if(!blocks->n) return strtod(\"NaN\", NULL);\n\n    //Iterate over the blocks\n    for(i=0; i<blocks->n; i++) {\n        v = getVals(fp, blocks, i, tid, start, end);\n        if(!v) goto error;\n        for(j=0; j<v->n; j++) {\n            coverage += v->vals[j]->nBases * v->vals[j]->scalar;\n            mean += v->vals[j]->sum * v->vals[j]->scalar;\n            ssq += v->vals[j]->sumsq * v->vals[j]->scalar;\n        }\n        destroyVals_t(v);\n        v = NULL;\n    }\n\n    if(coverage<=1.0) return strtod(\"NaN\", NULL);\n    diff = ssq-mean*mean/coverage;\n    if(coverage > 1.0) diff /= coverage-1;\n    if(fabs(diff) > 1e-8) { //Ignore floating point differences\n        return sqrt(diff);\n    } else {\n        return 0.0;\n    }\n\nerror:\n    if(v) destroyVals_t(v);\n    errno = ENOMEM;\n    return strtod(\"NaN\", NULL);\n}\n\n//This uses compensated summation to account for finite precision math\nstatic double intDev(bwOverlappingIntervals_t* ints, uint32_t start, uint32_t end) {\n    double v1 = 0.0, mean, rv;\n    uint32_t nBases = 0, i, start_use, end_use;\n\n    if(!ints->l) return strtod(\"NaN\", NULL);\n    mean = intMean(ints, start, end);\n\n    for(i=0; i<ints->l; i++) {\n        start_use = ints->start[i];\n        end_use = ints->end[i];\n        if(ints->start[i] < start) start_use = start;\n        if(ints->end[i] > end) end_use = end;\n        nBases += end_use-start_use;\n        v1 += (end_use-start_use) * pow(ints->value[i]-mean, 2.0); //running sum of squared difference\n    }\n\n    if(nBases>=2) rv = sqrt(v1/(nBases-1));\n    else if(nBases==1) rv = sqrt(v1);\n    else rv = strtod(\"NaN\", NULL);\n\n    return rv;\n}\n\nstatic double blockMax(bigWigFile_t *fp, bwOverlapBlock_t *blocks, uint32_t tid, uint32_t start, uint32_t end) {\n    uint32_t i, j, isNA = 1;\n    double o = strtod(\"NaN\", NULL);\n    struct vals_t *v = NULL;\n\n    if(!blocks->n) return o;\n\n    //Iterate the blocks\n    for(i=0; i<blocks->n; i++) {\n        v = getVals(fp, blocks, i, tid, start, end);\n        if(!v) goto error;\n        for(j=0; j<v->n; j++) {\n            if(isNA) {\n                o = v->vals[j]->max;\n                isNA = 0;\n            } else if(v->vals[j]->max > o) {\n                o = v->vals[j]->max;\n            }\n        }\n        destroyVals_t(v);\n    }\n\n    return o;\n\nerror:\n    destroyVals_t(v);\n    errno = ENOMEM;\n    return strtod(\"NaN\", NULL);\n}\n\nstatic double intMax(bwOverlappingIntervals_t* ints) {\n    uint32_t i;\n    double o;\n\n    if(ints->l < 1) return strtod(\"NaN\", NULL);\n\n    o = ints->value[0];\n    for(i=1; i<ints->l; i++) {\n        if(ints->value[i] > o) o = ints->value[i];\n    }\n\n    return o;\n}\n\nstatic double blockMin(bigWigFile_t *fp, bwOverlapBlock_t *blocks, uint32_t tid, uint32_t start, uint32_t end) {\n    uint32_t i, j, isNA = 1;\n    double o = strtod(\"NaN\", NULL);\n    struct vals_t *v = NULL;\n\n    if(!blocks->n) return o;\n\n    //Iterate the blocks\n    for(i=0; i<blocks->n; i++) {\n        v = getVals(fp, blocks, i, tid, start, end);\n        if(!v) goto error;\n        for(j=0; j<v->n; j++) {\n            if(isNA) {\n                o = v->vals[j]->min;\n                isNA = 0;\n            } else if(v->vals[j]->min < o) o = v->vals[j]->min;\n        }\n        destroyVals_t(v);\n    }\n\n    return o;\n\nerror:\n    destroyVals_t(v);\n    errno = ENOMEM;\n    return strtod(\"NaN\", NULL);\n}\n\nstatic double intMin(bwOverlappingIntervals_t* ints) {\n    uint32_t i;\n    double o;\n\n    if(ints->l < 1) return strtod(\"NaN\", NULL);\n\n    o = ints->value[0];\n    for(i=1; i<ints->l; i++) {\n        if(ints->value[i] < o) o = ints->value[i];\n    }\n\n    return o;\n}\n\n//Does UCSC compensate for only partial block/interval overlap?\nstatic double blockCoverage(bigWigFile_t *fp, bwOverlapBlock_t *blocks, uint32_t tid, uint32_t start, uint32_t end) {\n    uint32_t i, j;\n    double o = 0.0;\n    struct vals_t *v = NULL;\n\n    if(!blocks->n) return strtod(\"NaN\", NULL);\n\n    //Iterate over the blocks\n    for(i=0; i<blocks->n; i++) {\n        v = getVals(fp, blocks, i, tid, start, end);\n        if(!v) goto error;\n        for(j=0; j<v->n; j++) {\n            o+= v->vals[j]->nBases * v->vals[j]->scalar;\n        }\n        destroyVals_t(v);\n    }\n\n    if(o == 0.0) return strtod(\"NaN\", NULL);\n    return o;\n\nerror:\n    destroyVals_t(v);\n    errno = ENOMEM;\n    return strtod(\"NaN\", NULL);\n}\n\nstatic double intCoverage(bwOverlappingIntervals_t* ints, uint32_t start, uint32_t end) {\n    uint32_t i, start_use, end_use;\n    double o = 0.0;\n\n    if(!ints->l) return strtod(\"NaN\", NULL);\n\n    for(i=0; i<ints->l; i++) {\n        start_use = ints->start[i];\n        end_use = ints->end[i];\n        if(start_use < start) start_use = start;\n        if(end_use > end) end_use = end;\n        o += end_use - start_use;\n    }\n\n    return o/(end-start);\n}\n\nstatic double blockSum(bigWigFile_t *fp, bwOverlapBlock_t *blocks, uint32_t tid, uint32_t start, uint32_t end) {\n    uint32_t i, j, sizeUse;\n    double o = 0.0;\n    struct vals_t *v = NULL;\n\n    if(!blocks->n) return strtod(\"NaN\", NULL);\n\n    //Iterate over the blocks\n    for(i=0; i<blocks->n; i++) {\n        v = getVals(fp, blocks, i, tid, start, end);\n        if(!v) goto error;\n        for(j=0; j<v->n; j++) {\n            //Multiply the block average by min(bases covered, block overlap with interval)\n            sizeUse = v->vals[j]->scalar;\n            if(sizeUse > v->vals[j]->nBases) sizeUse = v->vals[j]->nBases;\n            o+= (v->vals[j]->sum * sizeUse) / v->vals[j]->nBases;\n        }\n        destroyVals_t(v);\n    }\n\n    if(o == 0.0) return strtod(\"NaN\", NULL);\n    return o;\n\nerror:\n    destroyVals_t(v);\n    errno = ENOMEM;\n    return strtod(\"NaN\", NULL);\n}\n\nstatic double intSum(bwOverlappingIntervals_t* ints, uint32_t start, uint32_t end) {\n    uint32_t i, start_use, end_use;\n    double o = 0.0;\n\n    if(!ints->l) return strtod(\"NaN\", NULL);\n\n    for(i=0; i<ints->l; i++) {\n        start_use = ints->start[i];\n        end_use = ints->end[i];\n        if(start_use < start) start_use = start;\n        if(end_use > end) end_use = end;\n        o += (end_use - start_use) * ints->value[i];\n    }\n\n    return o;\n}\n\n//Returns NULL on error, otherwise a double* that needs to be free()d\nstatic double *bwStatsFromZoom(bigWigFile_t *fp, int32_t level, uint32_t tid, uint32_t start, uint32_t end, uint32_t nBins, enum bwStatsType type) {\n    bwOverlapBlock_t *blocks = NULL;\n    double *output = NULL;\n    uint32_t pos = start, i, end2;\n\n    if(!fp->hdr->zoomHdrs->idx[level]) {\n        fp->hdr->zoomHdrs->idx[level] = bwReadIndex(fp, fp->hdr->zoomHdrs->indexOffset[level]);\n        if(!fp->hdr->zoomHdrs->idx[level]) return NULL;\n    }\n    errno = 0; //Sometimes libCurls sets and then doesn't unset errno on errors\n\n    output = malloc(sizeof(double)*nBins);\n    if(!output) return NULL;\n\n    for(i=0, pos=start; i<nBins; i++) {\n        end2 = start + ((double)(end-start)*(i+1))/((int) nBins);\n        blocks = walkRTreeNodes(fp, fp->hdr->zoomHdrs->idx[level]->root, tid, pos, end2);\n        if(!blocks) goto error;\n\n        switch(type) {\n        case 0:\n            //mean\n            output[i] = blockMean(fp, blocks, tid, pos, end2);\n            break;\n        case 1:\n            //stdev\n            output[i] = blockDev(fp, blocks, tid, pos, end2);\n            break;\n        case 2:\n            //max\n            output[i] = blockMax(fp, blocks, tid, pos, end2);\n            break;\n        case 3:\n            //min\n            output[i] = blockMin(fp, blocks, tid, pos, end2);\n            break;\n        case 4:\n            //cov\n            output[i] = blockCoverage(fp, blocks, tid, pos, end2)/(end2-pos);\n            break;\n        case 5:\n            //sum\n            output[i] = blockSum(fp, blocks, tid, pos, end2);\n            break;\n        default:\n            goto error;\n            break;\n        }\n        if(errno) goto error;\n        destroyBWOverlapBlock(blocks);\n        pos = end2;\n    }\n\n    return output;\n\nerror:\n    fprintf(stderr, \"got an error in bwStatsFromZoom in the range %\"PRIu32\"-%\"PRIu32\": %s\\n\", pos, end2, strerror(errno));\n    if(blocks) destroyBWOverlapBlock(blocks);\n    if(output) free(output);\n    return NULL;\n}\n\ndouble *bwStatsFromFull(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, uint32_t nBins, enum bwStatsType type) {\n    bwOverlappingIntervals_t *ints = NULL;\n    double *output = malloc(sizeof(double)*nBins);\n    uint32_t i, pos = start, end2;\n    if(!output) return NULL;\n\n    for(i=0; i<nBins; i++) {\n        end2 = start + ((double)(end-start)*(i+1))/((int) nBins);\n        ints = bwGetOverlappingIntervals(fp, chrom, pos, end2);\n\n        if(!ints) {\n            output[i] = strtod(\"NaN\", NULL);\n            continue;\n        }\n\n        switch(type) {\n        default :\n        case 0:\n            output[i] = intMean(ints, pos, end2);\n            break;\n        case 1:\n            output[i] = intDev(ints, pos, end2);\n            break;\n        case 2:\n            output[i] = intMax(ints);\n            break;\n        case 3:\n            output[i] = intMin(ints);\n            break;\n        case 4:\n            output[i] = intCoverage(ints, pos, end2);\n            break;\n        case 5:\n            output[i] = intSum(ints, pos, end2);\n            break;\n        }\n        bwDestroyOverlappingIntervals(ints);\n        pos = end2;\n    }\n\n    return output;\n}\n\n//Returns a list of floats of length nBins that must be free()d\n//On error, NULL is returned\ndouble *bwStats(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, uint32_t nBins, enum bwStatsType type) {\n    int32_t level = determineZoomLevel(fp, ((double)(end-start))/((int) nBins));\n    uint32_t tid = bwGetTid(fp, chrom);\n    if(tid == (uint32_t) -1) return NULL;\n\n    if(level == -1) return bwStatsFromFull(fp, chrom, start, end, nBins, type);\n    return bwStatsFromZoom(fp, level, tid, start, end, nBins, type);\n}\n"
  },
  {
    "path": "libBigWig/bwValues.c",
    "content": "#include \"bigWig.h\"\n#include \"bwCommon.h\"\n#include <stdlib.h>\n#include <math.h>\n#include <string.h>\n#include <zlib.h>\n#include <errno.h>\n\nstatic uint32_t roundup(uint32_t v) {\n    v--;\n    v |= v >> 1;\n    v |= v >> 2;\n    v |= v >> 4;\n    v |= v >> 8;\n    v |= v >> 16;\n    v++;\n    return v;\n}\n\n//Returns the root node on success and NULL on error\nstatic bwRTree_t *readRTreeIdx(bigWigFile_t *fp, uint64_t offset) {\n    uint32_t magic;\n    bwRTree_t *node;\n\n    if(!offset) {\n        if(bwSetPos(fp, fp->hdr->indexOffset)) return NULL;\n    } else {\n        if(bwSetPos(fp, offset)) return NULL;\n    }\n\n    if(bwRead(&magic, sizeof(uint32_t), 1, fp) != 1) return NULL;\n    if(magic != IDX_MAGIC) {\n        fprintf(stderr, \"[readRTreeIdx] Mismatch in the magic number!\\n\");\n        return NULL;\n    }\n\n    node = calloc(1, sizeof(bwRTree_t));\n    if(!node) return NULL;\n\n    if(bwRead(&(node->blockSize), sizeof(uint32_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->nItems), sizeof(uint64_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->chrIdxStart), sizeof(uint32_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->baseStart), sizeof(uint32_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->chrIdxEnd), sizeof(uint32_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->baseEnd), sizeof(uint32_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->idxSize), sizeof(uint64_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->nItemsPerSlot), sizeof(uint32_t), 1, fp) != 1) goto error;\n    //Padding\n    if(bwRead(&(node->blockSize), sizeof(uint32_t), 1, fp) != 1) goto error;\n    node->rootOffset = bwTell(fp);\n\n    //For remote files, libCurl sometimes sets errno to 115 and doesn't clear it\n    errno = 0;\n\n    return node;\n\nerror:\n    free(node);\n    return NULL;\n}\n\n//Returns a bwRTreeNode_t on success and NULL on an error\n//For the root node, set offset to 0\nstatic bwRTreeNode_t *bwGetRTreeNode(bigWigFile_t *fp, uint64_t offset) {\n    bwRTreeNode_t *node = NULL;\n    uint8_t padding;\n    uint16_t i;\n    if(offset) {\n        if(bwSetPos(fp, offset)) return NULL;\n    } else {\n        //seek\n        if(bwSetPos(fp, fp->idx->rootOffset)) return NULL;\n    }\n\n    node = calloc(1, sizeof(bwRTreeNode_t));\n    if(!node) return NULL;\n\n    if(bwRead(&(node->isLeaf), sizeof(uint8_t), 1, fp) != 1) goto error;\n    if(bwRead(&padding, sizeof(uint8_t), 1, fp) != 1) goto error;\n    if(bwRead(&(node->nChildren), sizeof(uint16_t), 1, fp) != 1) goto error;\n\n    node->chrIdxStart = malloc(sizeof(uint32_t)*(node->nChildren));\n    if(!node->chrIdxStart) goto error;\n    node->baseStart = malloc(sizeof(uint32_t)*(node->nChildren));\n    if(!node->baseStart) goto error;\n    node->chrIdxEnd = malloc(sizeof(uint32_t)*(node->nChildren));\n    if(!node->chrIdxEnd) goto error;\n    node->baseEnd = malloc(sizeof(uint32_t)*(node->nChildren));\n    if(!node->baseEnd) goto error;\n    node->dataOffset = malloc(sizeof(uint64_t)*(node->nChildren));\n    if(!node->dataOffset) goto error;\n    if(node->isLeaf) {\n        node->x.size = malloc(node->nChildren * sizeof(uint64_t));\n        if(!node->x.size) goto error;\n    } else {\n        node->x.child = calloc(node->nChildren, sizeof(struct bwRTreeNode_t *));\n        if(!node->x.child) goto error;\n    }\n    for(i=0; i<node->nChildren; i++) {\n        if(bwRead(&(node->chrIdxStart[i]), sizeof(uint32_t), 1, fp) != 1) goto error;\n        if(bwRead(&(node->baseStart[i]), sizeof(uint32_t), 1, fp) != 1) goto error;\n        if(bwRead(&(node->chrIdxEnd[i]), sizeof(uint32_t), 1, fp) != 1) goto error;\n        if(bwRead(&(node->baseEnd[i]), sizeof(uint32_t), 1, fp) != 1) goto error;\n        if(bwRead(&(node->dataOffset[i]), sizeof(uint64_t), 1, fp) != 1) goto error;\n        if(node->isLeaf) {\n            if(bwRead(&(node->x.size[i]), sizeof(uint64_t), 1, fp) != 1) goto error;\n        }\n    }\n\n    return node;\n\nerror:\n    if(node->chrIdxStart) free(node->chrIdxStart);\n    if(node->baseStart) free(node->baseStart);\n    if(node->chrIdxEnd) free(node->chrIdxEnd);\n    if(node->baseEnd) free(node->baseEnd);\n    if(node->dataOffset) free(node->dataOffset);\n    if(node->isLeaf && node->x.size) free(node->x.size);\n    else if((!node->isLeaf) && node->x.child) free(node->x.child);\n    free(node);\n    return NULL;\n}\n\nvoid destroyBWOverlapBlock(bwOverlapBlock_t *b) {\n    if(!b) return;\n    if(b->size) free(b->size);\n    if(b->offset) free(b->offset);\n    free(b);\n}\n\n//Returns a bwOverlapBlock_t * object or NULL on error.\nstatic bwOverlapBlock_t *overlapsLeaf(bwRTreeNode_t *node, uint32_t tid, uint32_t start, uint32_t end) {\n    uint16_t i, idx = 0;\n    bwOverlapBlock_t *o = calloc(1, sizeof(bwOverlapBlock_t));\n    if(!o) return NULL;\n\n    for(i=0; i<node->nChildren; i++) {\n        if(tid < node->chrIdxStart[i] || tid > node->chrIdxEnd[i]) continue;\n\n        /*\n          The individual blocks can theoretically span multiple contigs.\n          So if we treat the first/last contig in the range as special\n          but anything in the middle is a guaranteed match\n        */\n        if(node->chrIdxStart[i] != node->chrIdxEnd[i]) {\n            if(tid == node->chrIdxStart[i]) {\n                if(node->baseStart[i] >= end) break;\n            } else if(tid == node->chrIdxEnd[i]) {\n                if(node->baseEnd[i] <= start) continue;\n            }\n        } else {\n            if(node->baseStart[i] >= end || node->baseEnd[i] <= start) continue;\n        }\n        o->n++;\n    }\n\n    if(o->n) {\n        o->offset = malloc(sizeof(uint64_t) * (o->n));\n        if(!o->offset) goto error;\n        o->size = malloc(sizeof(uint64_t) * (o->n));\n        if(!o->size) goto error;\n\n        for(i=0; i<node->nChildren; i++) {\n            if(tid < node->chrIdxStart[i] || tid > node->chrIdxEnd[i]) continue;\n            if(node->chrIdxStart[i] != node->chrIdxEnd[i]) {\n                if(tid == node->chrIdxStart[i]) {\n                    if(node->baseStart[i] >= end) continue;\n                } else if(tid == node->chrIdxEnd[i]) {\n                    if(node->baseEnd[i] <= start) continue;\n                }\n            } else {\n                if(node->baseStart[i] >= end || node->baseEnd[i] <= start) continue;\n            }\n            o->offset[idx] = node->dataOffset[i];\n            o->size[idx++] = node->x.size[i];\n            if(idx >= o->n) break;\n        }\n    }\n\n    if(idx != o->n) { //This should never happen\n        fprintf(stderr, \"[overlapsLeaf] Mismatch between number of overlaps calculated and found!\\n\");\n        goto error;\n    }\n\n    return o;\n\nerror:\n    if(o) destroyBWOverlapBlock(o);\n    return NULL;\n}\n\n//This will free l2 unless there's an error!\n//Returns NULL on error, otherwise the merged lists\nstatic bwOverlapBlock_t *mergeOverlapBlocks(bwOverlapBlock_t *b1, bwOverlapBlock_t *b2) {\n    uint64_t i,j;\n    if(!b2) return b1;\n    if(!b2->n) {\n        destroyBWOverlapBlock(b2);\n        return b1;\n    }\n    if(!b1->n) {\n        destroyBWOverlapBlock(b1);\n        return b2;\n    }\n    j = b1->n;\n    b1->n += b2->n;\n    b1->offset = realloc(b1->offset, sizeof(uint64_t) * (b1->n+b2->n));\n    if(!b1->offset) goto error;\n    b1->size = realloc(b1->size, sizeof(uint64_t) * (b1->n+b2->n));\n    if(!b1->size) goto error;\n\n    for(i=0; i<b2->n; i++) {\n        b1->offset[j+i] = b2->offset[i];\n        b1->size[j+i] = b2->size[i];\n    }\n    destroyBWOverlapBlock(b2);\n    return b1;\n\nerror:\n    destroyBWOverlapBlock(b1);\n    return NULL;\n}\n\n//Returns NULL and sets nOverlaps to >0 on error, otherwise nOverlaps is the number of file offsets returned\n//The output needs to be free()d if not NULL (likewise with *sizes)\nstatic bwOverlapBlock_t *overlapsNonLeaf(bigWigFile_t *fp, bwRTreeNode_t *node, uint32_t tid, uint32_t start, uint32_t end) {\n    uint16_t i;\n    bwOverlapBlock_t *nodeBlocks, *output = calloc(1, sizeof(bwOverlapBlock_t));\n    if(!output) return NULL;\n\n    for(i=0; i<node->nChildren; i++) {\n        if(tid < node->chrIdxStart[i]) break;\n        if(tid < node->chrIdxStart[i] || tid > node->chrIdxEnd[i]) continue;\n        if(node->chrIdxStart[i] != node->chrIdxEnd[i]) { //child spans contigs\n            if(tid == node->chrIdxStart[i]) {\n                if(node->baseStart[i] >= end) continue;\n            } else if(tid == node->chrIdxEnd[i]) {\n                if(node->baseEnd[i] <= start) continue;\n            }\n        } else {\n            if(end <= node->baseStart[i] || start >= node->baseEnd[i]) continue;\n        }\n\n        //We have an overlap!\n        if(!node->x.child[i])\n          node->x.child[i] = bwGetRTreeNode(fp, node->dataOffset[i]);\n        if(!node->x.child[i]) goto error;\n\n        if(node->x.child[i]->isLeaf) { //leaf\n            nodeBlocks = overlapsLeaf(node->x.child[i], tid, start, end);\n        } else { //non-leaf\n            nodeBlocks = overlapsNonLeaf(fp, node->x.child[i], tid, start, end);\n        }\n\n        //The output is processed the same regardless of leaf/non-leaf\n        if(!nodeBlocks) goto error;\n        else {\n            output = mergeOverlapBlocks(output, nodeBlocks);\n            if(!output) {\n                destroyBWOverlapBlock(nodeBlocks);\n                goto error;\n            }\n        }\n    }\n\n    return output;\n\nerror:\n    destroyBWOverlapBlock(output);\n    return NULL;\n}\n\n//Returns NULL and sets nOverlaps to >0 on error, otherwise nOverlaps is the number of file offsets returned\n//The output must be free()d\nbwOverlapBlock_t *walkRTreeNodes(bigWigFile_t *bw, bwRTreeNode_t *root, uint32_t tid, uint32_t start, uint32_t end) {\n    if(root->isLeaf) return overlapsLeaf(root, tid, start, end);\n    return overlapsNonLeaf(bw, root, tid, start, end);\n}\n\n//In reality, a hash or some sort of tree structure is probably faster...\n//Return -1 (AKA 0xFFFFFFFF...) on \"not there\", so we can hold (2^32)-1 items.\nuint32_t bwGetTid(const bigWigFile_t *fp, const char *chrom) {\n    uint32_t i;\n    if(!chrom) return -1;\n    for(i=0; i<fp->cl->nKeys; i++) {\n        if(strcmp(chrom, fp->cl->chrom[i]) == 0) return i;\n    }\n    return -1;\n}\n\nstatic bwOverlapBlock_t *bwGetOverlappingBlocks(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end) {\n    uint32_t tid = bwGetTid(fp, chrom);\n\n    if(tid == (uint32_t) -1) {\n        fprintf(stderr, \"[bwGetOverlappingBlocks] Non-existent contig: %s\\n\", chrom);\n        return NULL;\n    }\n\n    //Get the info if needed\n    if(!fp->idx) {\n        fp->idx = readRTreeIdx(fp, fp->hdr->indexOffset);\n        if(!fp->idx) {\n            return NULL;\n        }\n    }\n\n    if(!fp->idx->root) fp->idx->root = bwGetRTreeNode(fp, 0);\n    if(!fp->idx->root) return NULL;\n\n    return walkRTreeNodes(fp, fp->idx->root, tid, start, end);\n}\n\nvoid bwFillDataHdr(bwDataHeader_t *hdr, void *b) {\n    hdr->tid = ((uint32_t*)b)[0];\n    hdr->start = ((uint32_t*)b)[1];\n    hdr->end = ((uint32_t*)b)[2];\n    hdr->step = ((uint32_t*)b)[3];\n    hdr->span = ((uint32_t*)b)[4];\n    hdr->type = ((uint8_t*)b)[20];\n    hdr->nItems = ((uint16_t*)b)[11];\n}\n\nvoid bwDestroyOverlappingIntervals(bwOverlappingIntervals_t *o) {\n    if(!o) return;\n    if(o->start) free(o->start);\n    if(o->end) free(o->end);\n    if(o->value) free(o->value);\n    free(o);\n}\n\nvoid bbDestroyOverlappingEntries(bbOverlappingEntries_t *o) {\n    uint32_t i;\n    if(!o) return;\n    if(o->start) free(o->start);\n    if(o->end) free(o->end);\n    if(o->str) {\n        for(i=0; i<o->l; i++) {\n            if(o->str[i]) free(o->str[i]);\n        }\n        free(o->str);\n    }\n    free(o);\n}\n\n//Returns NULL on error, in which case o has been free()d\nstatic bwOverlappingIntervals_t *pushIntervals(bwOverlappingIntervals_t *o, uint32_t start, uint32_t end, float value) {\n    if(o->l+1 >= o->m) {\n        o->m = roundup(o->l+1);\n        o->start = realloc(o->start, o->m * sizeof(uint32_t));\n        if(!o->start) goto error;\n        o->end = realloc(o->end, o->m * sizeof(uint32_t));\n        if(!o->end) goto error;\n        o->value = realloc(o->value, o->m * sizeof(float));\n        if(!o->value) goto error;\n    }\n    o->start[o->l] = start;\n    o->end[o->l] = end;\n    o->value[o->l++] = value;\n    return o;\n\nerror:\n    bwDestroyOverlappingIntervals(o);\n    return NULL;\n}\n\nstatic bbOverlappingEntries_t *pushBBIntervals(bbOverlappingEntries_t *o, uint32_t start, uint32_t end, char *str, int withString) {\n    if(o->l+1 >= o->m) {\n        o->m = roundup(o->l+1);\n        o->start = realloc(o->start, o->m * sizeof(uint32_t));\n        if(!o->start) goto error;\n        o->end = realloc(o->end, o->m * sizeof(uint32_t));\n        if(!o->end) goto error;\n        if(withString) {\n            o->str = realloc(o->str, o->m * sizeof(char**));\n            if(!o->str) goto error;\n        }\n    }\n    o->start[o->l] = start;\n    o->end[o->l] = end;\n    if(withString) o->str[o->l] = bwStrdup(str);\n    o->l++;\n    return o;\n\nerror:\n    bbDestroyOverlappingEntries(o);\n    return NULL;\n}\n\n//Returns NULL on error\nbwOverlappingIntervals_t *bwGetOverlappingIntervalsCore(bigWigFile_t *fp, bwOverlapBlock_t *o, uint32_t tid, uint32_t ostart, uint32_t oend) {\n    uint64_t i;\n    uint16_t j;\n    int compressed = 0, rv;\n    uLongf sz = fp->hdr->bufSize, tmp;\n    void *buf = NULL, *compBuf = NULL;\n    uint32_t start = 0, end , *p;\n    float value;\n    bwDataHeader_t hdr;\n    bwOverlappingIntervals_t *output = calloc(1, sizeof(bwOverlappingIntervals_t));\n\n    if(!output) goto error;\n\n    if(!o) return output;\n    if(!o->n) return output;\n\n    if(sz) {\n        compressed = 1;\n        buf = malloc(sz);\n    }\n    sz = 0; //This is now the size of the compressed buffer\n\n    for(i=0; i<o->n; i++) {\n        if(bwSetPos(fp, o->offset[i])) goto error;\n\n        if(sz < o->size[i]) {\n            compBuf = realloc(compBuf, o->size[i]);\n            sz = o->size[i];\n        }\n        if(!compBuf) goto error;\n\n        if(bwRead(compBuf, o->size[i], 1, fp) != 1) goto error;\n        if(compressed) {\n            tmp = fp->hdr->bufSize; //This gets over-written by uncompress\n            rv = uncompress(buf, (uLongf *) &tmp, compBuf, o->size[i]);\n            if(rv != Z_OK) goto error;\n        } else {\n            buf = compBuf;\n        }\n\n        //TODO: ensure that tmp is large enough!\n        bwFillDataHdr(&hdr, buf);\n\n        p = ((uint32_t*) buf);\n        p += 6;\n        if(hdr.tid != tid) continue;\n\n        if(hdr.type == 3) start = hdr.start - hdr.step;\n\n        //FIXME: We should ensure that sz is large enough to hold nItems of the given type\n        for(j=0; j<hdr.nItems; j++) {\n            switch(hdr.type) {\n            case 1:\n                start = *p;\n                p++;\n                end = *p;\n                p++;\n                value = *((float *)p);\n                p++;\n                break;\n            case 2:\n                start = *p;\n                p++;\n                end = start + hdr.span;\n                value = *((float *)p);\n                p++;\n                break;\n            case 3:\n                start += hdr.step;\n                end = start+hdr.span;\n                value = *((float *)p);\n                p++;\n                break;\n            default :\n                goto error;\n                break;\n            }\n\n            if(end <= ostart || start >= oend) continue;\n            //Push the overlap\n            if(!pushIntervals(output, start, end, value)) goto error;\n        }\n    }\n\n    if(compressed && buf) free(buf);\n    if(compBuf) free(compBuf);\n    return output;\n\nerror:\n    fprintf(stderr, \"[bwGetOverlappingIntervalsCore] Got an error\\n\");\n    if(output) bwDestroyOverlappingIntervals(output);\n    if(compressed && buf) free(buf);\n    if(compBuf) free(compBuf);\n    return NULL;\n}\n\nbbOverlappingEntries_t *bbGetOverlappingEntriesCore(bigWigFile_t *fp, bwOverlapBlock_t *o, uint32_t tid, uint32_t ostart, uint32_t oend, int withString) {\n    uint64_t i;\n    int compressed = 0, rv, slen;\n    uLongf sz = fp->hdr->bufSize, tmp = 0;\n    void *buf = NULL, *bufEnd = NULL, *compBuf = NULL;\n    uint32_t entryTid = 0, start = 0, end;\n    char *str;\n    bbOverlappingEntries_t *output = calloc(1, sizeof(bbOverlappingEntries_t));\n\n    if(!output) goto error;\n\n    if(!o) return output;\n    if(!o->n) return output;\n\n    if(sz) {\n        compressed = 1;\n        buf = malloc(sz);\n    }\n    sz = 0; //This is now the size of the compressed buffer\n\n    for(i=0; i<o->n; i++) {\n        if(bwSetPos(fp, o->offset[i])) goto error;\n\n        if(sz < o->size[i]) {\n            compBuf = realloc(compBuf, o->size[i]);\n            sz = o->size[i];\n        }\n        if(!compBuf) goto error;\n\n        if(bwRead(compBuf, o->size[i], 1, fp) != 1) goto error;\n        if(compressed) {\n            tmp = fp->hdr->bufSize; //This gets over-written by uncompress\n            rv = uncompress(buf, (uLongf *) &tmp, compBuf, o->size[i]);\n            if(rv != Z_OK) goto error;\n        } else {\n            buf = compBuf;\n            tmp = o->size[i]; //TODO: Is this correct? Do non-gzipped bigBeds exist?\n        }\n\n        bufEnd = (char*)buf + tmp;\n        while(buf < bufEnd) {\n            entryTid = ((uint32_t*)buf)[0];\n            start = ((uint32_t*)buf)[1];\n            end = ((uint32_t*)buf)[2];\n            buf = (char*)buf + 12;\n            str = (char*)buf;\n            slen = strlen(str) + 1;\n            buf = (char*)buf + slen;\n\n            if(entryTid < tid) continue;\n            if(entryTid > tid) break;\n            if(end <= ostart) continue;\n            if(start >= oend) break;\n\n            //Push the overlap\n            if(!pushBBIntervals(output, start, end, str, withString)) goto error;\n        }\n\n        buf = (char*)bufEnd - tmp; //reset the buffer pointer\n    }\n\n    if(compressed && buf) free(buf);\n    if(compBuf) free(compBuf);\n    return output;\n\nerror:\n    fprintf(stderr, \"[bbGetOverlappingEntriesCore] Got an error\\n\");\n    buf = (char*)bufEnd - tmp;\n    if(output) bbDestroyOverlappingEntries(output);\n    if(compressed && buf) free(buf);\n    if(compBuf) free(compBuf);\n    return NULL;\n}\n\n//Returns NULL on error OR no intervals, which is a bad design...\nbwOverlappingIntervals_t *bwGetOverlappingIntervals(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end) {\n    bwOverlappingIntervals_t *output;\n    uint32_t tid = bwGetTid(fp, chrom);\n    if(tid == (uint32_t) -1) return NULL;\n    bwOverlapBlock_t *blocks = bwGetOverlappingBlocks(fp, chrom, start, end);\n    if(!blocks) return NULL;\n    output = bwGetOverlappingIntervalsCore(fp, blocks, tid, start, end);\n    destroyBWOverlapBlock(blocks);\n    return output;\n}\n\n//Like above, but for bigBed files\nbbOverlappingEntries_t *bbGetOverlappingEntries(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, int withString) {\n    bbOverlappingEntries_t *output;\n    uint32_t tid = bwGetTid(fp, chrom);\n    if(tid == (uint32_t) -1) return NULL;\n    bwOverlapBlock_t *blocks = bwGetOverlappingBlocks(fp, chrom, start, end);\n    if(!blocks) return NULL;\n    output = bbGetOverlappingEntriesCore(fp, blocks, tid, start, end, withString);\n    destroyBWOverlapBlock(blocks);\n    return output;\n}\n\n//Returns NULL on error\nbwOverlapIterator_t *bwOverlappingIntervalsIterator(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, uint32_t blocksPerIteration) {\n    bwOverlapIterator_t *output = NULL;\n    uint64_t n;\n    uint32_t tid = bwGetTid(fp, chrom);\n    if(tid == (uint32_t) -1) return output;\n    output = calloc(1, sizeof(bwOverlapIterator_t));\n    if(!output) return output;\n    bwOverlapBlock_t *blocks = bwGetOverlappingBlocks(fp, chrom, start, end);\n\n    output->bw = fp;\n    output->tid = tid;\n    output->start = start;\n    output->end = end;\n    output->blocks = blocks;\n    output->blocksPerIteration = blocksPerIteration;\n\n    if(blocks) {\n        n = blocks->n;\n        if(n>blocksPerIteration) blocks->n = blocksPerIteration;\n        output->intervals = bwGetOverlappingIntervalsCore(fp, blocks,tid, start, end);\n        blocks->n = n;\n        output->offset = blocksPerIteration;\n    }\n    output->data = output->intervals;\n    return output;\n}\n\n//Returns NULL on error\nbwOverlapIterator_t *bbOverlappingEntriesIterator(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, int withString, uint32_t blocksPerIteration) {\n    bwOverlapIterator_t *output = NULL;\n    uint64_t n;\n    uint32_t tid = bwGetTid(fp, chrom);\n    if(tid == (uint32_t) -1) return output;\n    output = calloc(1, sizeof(bwOverlapIterator_t));\n    if(!output) return output;\n    bwOverlapBlock_t *blocks = bwGetOverlappingBlocks(fp, chrom, start, end);\n\n    output->bw = fp;\n    output->tid = tid;\n    output->start = start;\n    output->end = end;\n    output->blocks = blocks;\n    output->blocksPerIteration = blocksPerIteration;\n    output->withString = withString;\n\n    if(blocks) {\n        n = blocks->n;\n        if(n>blocksPerIteration) blocks->n = blocksPerIteration;\n        output->entries = bbGetOverlappingEntriesCore(fp, blocks,tid, start, end, withString);\n        blocks->n = n;\n        output->offset = blocksPerIteration;\n    }\n    output->data = output->entries;\n    return output;\n}\n\nvoid bwIteratorDestroy(bwOverlapIterator_t *iter) {\n    if(!iter) return;\n    if(iter->blocks) destroyBWOverlapBlock((bwOverlapBlock_t*) iter->blocks);\n    if(iter->intervals) bwDestroyOverlappingIntervals(iter->intervals);\n    if(iter->entries) bbDestroyOverlappingEntries(iter->entries);\n    free(iter);\n}\n\n//On error, points to NULL and destroys the input\nbwOverlapIterator_t *bwIteratorNext(bwOverlapIterator_t *iter) {\n    uint64_t n, *offset, *size;\n    bwOverlapBlock_t *blocks = iter->blocks;\n\n    if(iter->intervals) {\n        bwDestroyOverlappingIntervals(iter->intervals);\n        iter->intervals = NULL;\n    }\n    if(iter->entries) {\n        bbDestroyOverlappingEntries(iter->entries);\n        iter->entries = NULL;\n    }\n    iter->data = NULL;\n\n    if(iter->offset < blocks->n) {\n        //store the previous values\n        n = blocks->n;\n        offset = blocks->offset;\n        size = blocks->size;\n\n        //Move the start of the blocks\n        blocks->offset += iter->offset;\n        blocks->size += iter->offset;\n        if(iter->offset + iter->blocksPerIteration > n) {\n            blocks->n = blocks->n - iter->offset;\n        } else {\n            blocks->n = iter->blocksPerIteration;\n        }\n\n        //Get the intervals or entries, as appropriate\n        if(iter->bw->type == 0) {\n            //bigWig\n            iter->intervals = bwGetOverlappingIntervalsCore(iter->bw, blocks, iter->tid, iter->start, iter->end);\n            iter->data = iter->intervals;\n        } else {\n            //bigBed\n            iter->entries = bbGetOverlappingEntriesCore(iter->bw, blocks, iter->tid, iter->start, iter->end, iter->withString);\n            iter->data = iter->entries;\n        }\n        iter->offset += iter->blocksPerIteration;\n\n        //reset the values in iter->blocks\n        blocks->n = n;\n        blocks->offset = offset;\n        blocks->size = size;\n\n        //Check for error\n        if(!iter->intervals && !iter->entries) goto error;\n    }\n\n    return iter;\n\nerror:\n    bwIteratorDestroy(iter);\n    return NULL;\n}\n\n//This is like bwGetOverlappingIntervals, except it returns 1 base windows. If includeNA is not 0, then a value will be returned for every position in the range (defaulting to NAN).\n//The ->end member is NULL\n//If includeNA is not 0 then ->start is also NULL, since it's implied\n//Note that bwDestroyOverlappingIntervals() will work in either case\nbwOverlappingIntervals_t *bwGetValues(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t end, int includeNA) {\n    uint32_t i, j, n;\n    bwOverlappingIntervals_t *output = NULL;\n    bwOverlappingIntervals_t *intermediate = bwGetOverlappingIntervals(fp, chrom, start, end);\n    if(!intermediate) return NULL;\n\n    output = calloc(1, sizeof(bwOverlappingIntervals_t));\n    if(!output) goto error;\n    if(includeNA) {\n        output->l = end-start;\n        output->value = malloc(output->l*sizeof(float));\n        if(!output->value) goto error;\n        for(i=0; i<output->l; i++) output->value[i] = NAN;\n        for(i=0; i<intermediate->l; i++) {\n            for(j=intermediate->start[i]; j<intermediate->end[i]; j++) {\n                if(j < start || j >= end) continue;\n                output->value[j-start] = intermediate->value[i];\n            }\n        }\n    } else {\n        n = 0;\n        for(i=0; i<intermediate->l; i++) {\n            if(intermediate->start[i] < start) intermediate->start[i] = start;\n            if(intermediate->end[i] > end) intermediate->end[i] = end;\n            n += intermediate->end[i]-intermediate->start[i];\n        }\n        output->l = n;\n        output->start = malloc(sizeof(uint32_t)*n);\n        if(!output->start) goto error;\n        output->value = malloc(sizeof(float)*n);\n        if(!output->value) goto error;\n        n = 0; //this is now the index\n        for(i=0; i<intermediate->l; i++) {\n            for(j=intermediate->start[i]; j<intermediate->end[i]; j++) {\n                if(j < start || j >= end) continue;\n                output->start[n] = j;\n                output->value[n++] = intermediate->value[i];\n            }\n        }\n    }\n\n    bwDestroyOverlappingIntervals(intermediate);\n    return output;\n\nerror:\n    if(intermediate) bwDestroyOverlappingIntervals(intermediate);\n    if(output) bwDestroyOverlappingIntervals(output);\n    return NULL;\n}\n\nvoid bwDestroyIndexNode(bwRTreeNode_t *node) {\n    uint16_t i;\n\n    if(!node) return;\n\n    free(node->chrIdxStart);\n    free(node->baseStart);\n    free(node->chrIdxEnd);\n    free(node->baseEnd);\n    free(node->dataOffset);\n    if(!node->isLeaf) {\n        for(i=0; i<node->nChildren; i++) {\n            bwDestroyIndexNode(node->x.child[i]);\n        }\n        free(node->x.child);\n    } else {\n        free(node->x.size);\n    }\n    free(node);\n}\n\nvoid bwDestroyIndex(bwRTree_t *idx) {\n    bwDestroyIndexNode(idx->root);\n    free(idx);\n}\n\n//Returns a pointer to the requested index (@offset, unless it's 0, in which case the index for the values is returned\n//Returns NULL on error\nbwRTree_t *bwReadIndex(bigWigFile_t *fp, uint64_t offset) {\n    bwRTree_t *idx = readRTreeIdx(fp, offset);\n    if(!idx) return NULL;\n\n    //Read in the root node\n    idx->root = bwGetRTreeNode(fp, idx->rootOffset);\n\n    if(!idx->root) {\n        bwDestroyIndex(idx);\n        return NULL;\n    }\n    return idx;\n}\n"
  },
  {
    "path": "libBigWig/bwValues.h",
    "content": "#ifndef LIBBIGWIG_VALUES_H\n#define LIBBIGWIG_VALUES_H\n\n#include <inttypes.h>\n/*! \\file bwValues.h\n *\n * You should not directly use functions and structures defined here. They're really meant for internal use only.\n *\n * All of the structures here need to be destroyed or you'll leak memory! There are methods available to destroy anything that you need to take care of yourself.\n */\n\n//N.B., coordinates are still 0-based half open!\n/*!\n * @brief A node within an R-tree holding the index for data.\n *\n * Note that there are two types of nodes: leaf and twig. Leaf nodes point to where data actually is. Twig nodes point to additional index nodes, which may or may not be leaves. Each of these nodes has additional children, which may span multiple chromosomes/contigs.\n *\n * With the start/end position, these positions refer specifically to the chromosomes specified in chrIdxStart/chrIdxEnd. Any chromosomes between these are completely spanned by a given child.\n */\ntypedef struct bwRTreeNode_t {\n    uint8_t isLeaf; /**<Is this node a leaf?*/\n    //1 byte of padding\n    uint16_t nChildren; /**<The number of children of this node, all lists have this length.*/\n    uint32_t *chrIdxStart; /**<A list of the starting chromosome indices of each child.*/\n    uint32_t *baseStart; /**<A list of the start position of each child.*/\n    uint32_t *chrIdxEnd; /**<A list of the end chromosome indices of each child.*/\n    uint32_t *baseEnd; /**<A list of the end position of each child.*/\n    uint64_t *dataOffset; /**<For leaves, the offset to the on-disk data. For twigs, the offset to the child node.*/\n    union {\n        uint64_t *size; /**<Leaves only: The size of the data block.*/\n        struct bwRTreeNode_t **child; /**<Twigs only: The child node(s).*/\n    } x; /**<A union holding either size or child*/\n} bwRTreeNode_t;\n\n/*!\n * A header and index that points to an R-tree that in turn points to data blocks.\n */\n//TODO rootOffset is pointless, it's 48bytes after the indexOffset\ntypedef struct {\n    uint32_t blockSize; /**<The maximum number of children a node can have*/\n    uint64_t nItems; /**<The total number of data blocks pointed to by the tree. This is completely redundant.*/\n    uint32_t chrIdxStart; /**<The index to the first chromosome described.*/\n    uint32_t baseStart; /**<The first position on chrIdxStart with a value.*/\n    uint32_t chrIdxEnd; /**<The index of the last chromosome with an entry.*/\n    uint32_t baseEnd; /**<The last position on chrIdxEnd with an entry.*/\n    uint64_t idxSize; /**<This is actually the offset of the index rather than the size?!? Yes, it's completely redundant.*/\n    uint32_t nItemsPerSlot; /**<This is always 1!*/\n    //There's 4 bytes of padding in the file here\n    uint64_t rootOffset; /**<The offset to the root node of the R-Tree (on disk). Yes, this is redundant.*/\n    bwRTreeNode_t *root; /**<A pointer to the root node.*/\n} bwRTree_t;\n\n/*!\n * @brief This structure holds the data blocks that overlap a given interval.\n */\ntypedef struct {\n    uint64_t n; /**<The number of blocks that overlap. This *MAY* be 0!.*/\n    uint64_t *offset; /**<The offset to the on-disk position of the block.*/\n    uint64_t *size; /**<The size of each block on disk (in bytes).*/\n} bwOverlapBlock_t;\n\n/*!\n * @brief The header section of a given data block.\n *\n * There are 3 types of data blocks in bigWig files, each with slightly different needs. This is all taken care of internally.\n */\ntypedef struct {\n    uint32_t tid; /**<The chromosome ID.*/\n    uint32_t start; /**<The start position of a block*/\n    uint32_t end; /**<The end position of a block*/\n    uint32_t step; /**<The step size of the values*/\n    uint32_t span; /**<The span of each data value*/\n    uint8_t type; /**<The block type: 1, bedGraph; 2, variable step; 3, fixed step.*/\n    uint16_t nItems; /**<The number of values in a given block.*/\n} bwDataHeader_t;\n\n#endif // LIBBIGWIG_VALUES_H\n"
  },
  {
    "path": "libBigWig/bwWrite.c",
    "content": "#include <limits.h>\n#include <float.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n#include \"bigWig.h\"\n#include \"bwCommon.h\"\n\n/// @cond SKIP\nstruct val_t {\n    uint32_t tid;\n    uint32_t start;\n    uint32_t nBases;\n    float min, max, sum, sumsq;\n    double scalar;\n    struct val_t *next;\n};\n/// @endcond\n\n//Create a chromList_t and attach it to a bigWigFile_t *. Returns NULL on error\n//Note that chroms and lengths are duplicated, so you MUST free the input\nchromList_t *bwCreateChromList(const char* const* chroms, const uint32_t *lengths, int64_t n) {\n    int64_t i = 0;\n    chromList_t *cl = calloc(1, sizeof(chromList_t));\n    if(!cl) return NULL;\n\n    cl->nKeys = n;\n    cl->chrom = malloc(sizeof(char*)*n);\n    cl->len = malloc(sizeof(uint32_t)*n);\n    if(!cl->chrom) goto error;\n    if(!cl->len) goto error;\n\n    for(i=0; i<n; i++) {\n        cl->len[i] = lengths[i];\n        cl->chrom[i] = bwStrdup(chroms[i]);\n        if(!cl->chrom[i]) goto error;\n    }\n\n    return cl;\n\nerror:\n    if(i) {\n        int64_t j;\n        for(j=0; j<i; j++) free(cl->chrom[j]);\n    }\n    if(cl) {\n        if(cl->chrom) free(cl->chrom);\n        if(cl->len) free(cl->len);\n        free(cl);\n    }\n    return NULL;\n}\n\n//If maxZooms == 0, then 0 is used (i.e., there are no zoom levels). If maxZooms < 0 or > 65535 then 10 is used.\n//TODO allow changing bufSize and blockSize\nint bwCreateHdr(bigWigFile_t *fp, int32_t maxZooms) {\n    if(!fp->isWrite) return 1;\n    bigWigHdr_t *hdr = calloc(1, sizeof(bigWigHdr_t));\n    if(!hdr) return 2;\n\n    hdr->version = 4;\n    if(maxZooms < 0 || maxZooms > 65535) {\n        hdr->nLevels = 10;\n    } else {\n        hdr->nLevels = maxZooms;\n    }\n\n    hdr->bufSize = 32768; //When the file is finalized this is reset if fp->writeBuffer->compressPsz is 0!\n    hdr->minVal = DBL_MAX;\n    hdr->maxVal = DBL_MIN;\n    fp->hdr = hdr;\n    fp->writeBuffer->blockSize = 64;\n\n    //Allocate the writeBuffer buffers\n    fp->writeBuffer->compressPsz = compressBound(hdr->bufSize);\n    fp->writeBuffer->compressP = malloc(fp->writeBuffer->compressPsz);\n    if(!fp->writeBuffer->compressP) return 3;\n    fp->writeBuffer->p = calloc(1,hdr->bufSize);\n    if(!fp->writeBuffer->p) return 4;\n\n    return 0;\n}\n\n//return 0 on success\nstatic int writeAtPos(void *ptr, size_t sz, size_t nmemb, size_t pos, FILE *fp) {\n    size_t curpos = ftell(fp);\n    if(fseek(fp, pos, SEEK_SET)) return 1;\n    if(fwrite(ptr, sz, nmemb, fp) != nmemb) return 2;\n    if(fseek(fp, curpos, SEEK_SET)) return 3;\n    return 0;\n}\n\n//We lose keySize bytes on error\nstatic int writeChromList(FILE *fp, chromList_t *cl) {\n    uint16_t k;\n    uint32_t j, magic = CIRTREE_MAGIC;\n    uint32_t nperblock = (cl->nKeys > 0x7FFF) ? 0x7FFF : cl->nKeys; //Items per leaf/non-leaf, there are no unsigned ints in java :(\n    uint32_t nblocks, keySize = 0, valSize = 8; //In theory valSize could be optimized, in practice that'd be annoying\n    uint64_t i, nonLeafEnd, leafSize, nextLeaf;\n    uint8_t eight;\n    int64_t i64;\n    char *chrom;\n    size_t l;\n\n    if(cl->nKeys > 1073676289) {\n        fprintf(stderr, \"[writeChromList] Error: Currently only 1,073,676,289 contigs are supported. If you really need more then please post a request on github.\\n\");\n        return 1;\n    }\n    nblocks = cl->nKeys/nperblock;\n    nblocks += ((cl->nKeys % nperblock) > 0)?1:0;\n\n    for(i64=0; i64<cl->nKeys; i64++) {\n        l = strlen(cl->chrom[i64]);\n        if(l>keySize) keySize = l;\n    }\n    l--; //We don't null terminate strings, because schiess mich tot\n    chrom = calloc(keySize, sizeof(char));\n\n    //Write the root node of a largely pointless tree\n    if(fwrite(&magic, sizeof(uint32_t), 1, fp) != 1) return 1;\n    if(fwrite(&nperblock, sizeof(uint32_t), 1, fp) != 1) return 2;\n    if(fwrite(&keySize, sizeof(uint32_t), 1, fp) != 1) return 3;\n    if(fwrite(&valSize, sizeof(uint32_t), 1, fp) != 1) return 4;\n    if(fwrite(&(cl->nKeys), sizeof(uint64_t), 1, fp) != 1) return 5;\n\n    //Padding?\n    i=0;\n    if(fwrite(&i, sizeof(uint64_t), 1, fp) != 1) return 6;\n\n    //Do we need a non-leaf node?\n    if(nblocks > 1) {\n        eight = 0;\n        if(fwrite(&eight, sizeof(uint8_t), 1, fp) != 1) return 7;\n        if(fwrite(&eight, sizeof(uint8_t), 1, fp) != 1) return 8; //padding\n        if(fwrite(&nblocks, sizeof(uint16_t), 1, fp) != 1) return 8;\n        nonLeafEnd = ftell(fp) + nperblock * (keySize + 8);\n        leafSize = nperblock * (keySize + 8) + 4;\n        for(i=0; i<nblocks; i++) { //Why yes, this is pointless\n            chrom = strncpy(chrom, cl->chrom[i * nperblock], keySize);\n            nextLeaf = nonLeafEnd + i * leafSize;\n            if(fwrite(chrom, keySize, 1, fp) != 1) return 9;\n            if(fwrite(&nextLeaf, sizeof(uint64_t), 1, fp) != 1) return 10;\n        }\n        for(i=0; i<keySize; i++) chrom[i] = '\\0';\n        nextLeaf = 0;\n        for(i=nblocks; i<nperblock; i++) {\n            if(fwrite(chrom, keySize, 1, fp) != 1) return 9;\n            if(fwrite(&nextLeaf, sizeof(uint64_t), 1, fp) != 1) return 10;\n        }\n    }\n\n    //Write the leaves\n    nextLeaf = 0;\n    for(i=0, j=0; i<nblocks; i++) {\n        eight = 1;\n        if(fwrite(&eight, sizeof(uint8_t), 1, fp) != 1) return 11;\n        eight = 0;\n        if(fwrite(&eight, sizeof(uint8_t), 1, fp) != 1) return 12;\n        if(cl->nKeys - j < nperblock) {\n            k = cl->nKeys - j;\n            if(fwrite(&k, sizeof(uint16_t), 1, fp) != 1) return 13;\n        } else {\n            if(fwrite(&nperblock, sizeof(uint16_t), 1, fp) != 1) return 13;\n        }\n        for(k=0; k<nperblock; k++) {\n            if(j>=cl->nKeys) {\n                if(chrom[0]) {\n                    for(l=0; l<keySize; l++) chrom[l] = '\\0';\n                }\n                if(fwrite(chrom, keySize, 1, fp) != 1) return 15;\n                if(fwrite(&nextLeaf, sizeof(uint64_t), 1, fp) != 1) return 16;\n            } else {\n                chrom = strncpy(chrom, cl->chrom[j], keySize);\n                if(fwrite(chrom, keySize, 1, fp) != 1) return 15;\n                if(fwrite(&j, sizeof(uint32_t), 1, fp) != 1) return 16;\n                if(fwrite(&(cl->len[j++]), sizeof(uint32_t), 1, fp) != 1) return 17;\n            }\n        }\n    }\n\n    free(chrom);\n    return 0;\n}\n\n//returns 0 on success\n//Still need to fill in indexOffset\nint bwWriteHdr(bigWigFile_t *bw) {\n    uint32_t magic = BIGWIG_MAGIC;\n    uint16_t two = 4;\n    FILE *fp;\n    const uint8_t pbuff[58] = {0}; // 58 bytes of nothing\n    const void *p = (const void *)&pbuff;\n    if(!bw->isWrite) return 1;\n\n    //The header itself, largely just reserving space...\n    fp = bw->URL->x.fp;\n    if(!fp) return 2;\n    if(fseek(fp, 0, SEEK_SET)) return 3;\n    if(fwrite(&magic, sizeof(uint32_t), 1, fp) != 1) return 4;\n    if(fwrite(&two, sizeof(uint16_t), 1, fp) != 1) return 5;\n    if(fwrite(p, sizeof(uint8_t), 58, fp) != 58) return 6;\n\n    //Empty zoom headers\n    if(bw->hdr->nLevels) {\n        for(two=0; two<bw->hdr->nLevels; two++) {\n            if(fwrite(p, sizeof(uint8_t), 24, fp) != 24) return 9;\n        }\n    }\n\n    //Update summaryOffset and write an empty summary block\n    bw->hdr->summaryOffset = ftell(fp);\n    if(fwrite(p, sizeof(uint8_t), 40, fp) != 40) return 10;\n    if(writeAtPos(&(bw->hdr->summaryOffset), sizeof(uint64_t), 1, 0x2c, fp)) return 11;\n\n    //Write the chromosome list as a stupid freaking tree (because let's TREE ALL THE THINGS!!!)\n    bw->hdr->ctOffset = ftell(fp);\n    if(writeChromList(fp, bw->cl)) return 7;\n    if(writeAtPos(&(bw->hdr->ctOffset), sizeof(uint64_t), 1, 0x8, fp)) return 8;\n\n    //Update the dataOffset\n    bw->hdr->dataOffset = ftell(fp);\n    if(writeAtPos(&bw->hdr->dataOffset, sizeof(uint64_t), 1, 0x10, fp)) return 12;\n\n    //Save space for the number of blocks\n    if(fwrite(p, sizeof(uint8_t), 8, fp) != 8) return 13;\n\n    return 0;\n}\n\nstatic int insertIndexNode(bigWigFile_t *fp, bwRTreeNode_t *leaf) {\n    bwLL *l = malloc(sizeof(bwLL));\n    if(!l) return 1;\n    l->node = leaf;\n    l->next = NULL;\n\n    if(!fp->writeBuffer->firstIndexNode) {\n        fp->writeBuffer->firstIndexNode = l;\n    } else {\n        fp->writeBuffer->currentIndexNode->next = l;\n    }\n    fp->writeBuffer->currentIndexNode = l;\n    return 0;\n}\n\n//0 on success\nstatic int appendIndexNodeEntry(bigWigFile_t *fp, uint32_t tid0, uint32_t tid1, uint32_t start, uint32_t end, uint64_t offset, uint64_t size) {\n    bwLL *n = fp->writeBuffer->currentIndexNode;\n    if(!n) return 1;\n    if(n->node->nChildren >= fp->writeBuffer->blockSize) return 2;\n\n    n->node->chrIdxStart[n->node->nChildren] = tid0;\n    n->node->baseStart[n->node->nChildren] = start;\n    n->node->chrIdxEnd[n->node->nChildren] = tid1;\n    n->node->baseEnd[n->node->nChildren] = end;\n    n->node->dataOffset[n->node->nChildren] = offset;\n    n->node->x.size[n->node->nChildren] = size;\n    n->node->nChildren++;\n    return 0;\n}\n\n//Returns 0 on success\nstatic int addIndexEntry(bigWigFile_t *fp, uint32_t tid0, uint32_t tid1, uint32_t start, uint32_t end, uint64_t offset, uint64_t size) {\n    bwRTreeNode_t *node;\n\n    if(appendIndexNodeEntry(fp, tid0, tid1, start, end, offset, size)) {\n        //The last index node is full, we need to add a new one\n        node = calloc(1, sizeof(bwRTreeNode_t));\n        if(!node) return 1;\n\n        //Allocate and set the fields\n        node->isLeaf = 1;\n        node->nChildren = 1;\n        node->chrIdxStart = malloc(sizeof(uint32_t)*fp->writeBuffer->blockSize);\n        if(!node->chrIdxStart) goto error;\n        node->baseStart = malloc(sizeof(uint32_t)*fp->writeBuffer->blockSize);\n        if(!node->baseStart) goto error;\n        node->chrIdxEnd = malloc(sizeof(uint32_t)*fp->writeBuffer->blockSize);\n        if(!node->chrIdxEnd) goto error;\n        node->baseEnd = malloc(sizeof(uint32_t)*fp->writeBuffer->blockSize);\n        if(!node->baseEnd) goto error;\n        node->dataOffset = malloc(sizeof(uint64_t)*fp->writeBuffer->blockSize);\n        if(!node->dataOffset) goto error;\n        node->x.size = malloc(sizeof(uint64_t)*fp->writeBuffer->blockSize);\n        if(!node->x.size) goto error;\n\n        node->chrIdxStart[0] = tid0;\n        node->baseStart[0] = start;\n        node->chrIdxEnd[0] = tid1;\n        node->baseEnd[0] = end;\n        node->dataOffset[0] = offset;\n        node->x.size[0] = size;\n\n        if(insertIndexNode(fp, node)) goto error;\n    }\n\n    return 0;\n\nerror:\n    if(node->chrIdxStart) free(node->chrIdxStart);\n    if(node->baseStart) free(node->baseStart);\n    if(node->chrIdxEnd) free(node->chrIdxEnd);\n    if(node->baseEnd) free(node->baseEnd);\n    if(node->dataOffset) free(node->dataOffset);\n    if(node->x.size) free(node->x.size);\n    return 2;\n}\n\n/*\n * TODO:\n *     The buffer size and compression sz need to be determined elsewhere (and p and compressP filled in!)\n */\nstatic int flushBuffer(bigWigFile_t *fp) {\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    uLongf sz = wb->compressPsz;\n    uint16_t nItems;\n    if(!fp->writeBuffer->l) return 0;\n    if(!wb->ltype) return 0;\n\n    //Fill in the header\n    if(!memcpy((char*)wb->p, &(wb->tid), sizeof(uint32_t))) return 1;\n    if(!memcpy((char*)wb->p+4, &(wb->start), sizeof(uint32_t))) return 2;\n    if(!memcpy((char*)wb->p+8, &(wb->end), sizeof(uint32_t))) return 3;\n    if(!memcpy((char*)wb->p+12, &(wb->step), sizeof(uint32_t))) return 4;\n    if(!memcpy((char*)wb->p+16, &(wb->span), sizeof(uint32_t))) return 5;\n    if(!memcpy((char*)wb->p+20, &(wb->ltype), sizeof(uint8_t))) return 6;\n    //1 byte padding\n    //Determine the number of items\n    switch(wb->ltype) {\n    case 1:\n        nItems = (wb->l-24)/12;\n        break;\n    case 2:\n        nItems = (wb->l-24)/8;\n        break;\n    case 3:\n        nItems = (wb->l-24)/4;\n        break;\n    default:\n        return 7;\n    }\n    if(!memcpy((char*)wb->p+22, &nItems, sizeof(uint16_t))) return 8;\n\n    if(sz) {\n        //compress\n        if(compress(wb->compressP, &sz, wb->p, wb->l) != Z_OK) return 9;\n\n        //write the data to disk\n        if(fwrite(wb->compressP, sizeof(uint8_t), sz, fp->URL->x.fp) != sz) return 10;\n    } else {\n        sz = wb->l;\n        if(fwrite(wb->p, sizeof(uint8_t), wb->l, fp->URL->x.fp) != wb->l) return 10;\n    }\n\n    //Add an entry into the index\n    if(addIndexEntry(fp, wb->tid, wb->tid, wb->start, wb->end, bwTell(fp)-sz, sz)) return 11;\n\n    wb->nBlocks++;\n    wb->l = 24;\n    return 0;\n}\n\nstatic void updateStats(bigWigFile_t *fp, uint32_t span, float val) {\n    if(val < fp->hdr->minVal) fp->hdr->minVal = val;\n    else if(val > fp->hdr->maxVal) fp->hdr->maxVal = val;\n    fp->hdr->nBasesCovered += span;\n    fp->hdr->sumData += span*val;\n    fp->hdr->sumSquared += span*pow(val,2);\n\n    fp->writeBuffer->nEntries++;\n    fp->writeBuffer->runningWidthSum += span;\n}\n\n//12 bytes per entry\nint bwAddIntervals(bigWigFile_t *fp, const char* const* chrom, const uint32_t *start, const uint32_t *end, const float *values, uint32_t n) {\n    uint32_t tid = 0, i;\n    const char *lastChrom = NULL;\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    if(!n) return 0; //Not an error per se\n    if(!fp->isWrite) return 1;\n    if(!wb) return 2;\n\n    //Flush if needed\n    if(wb->ltype != 1) if(flushBuffer(fp)) return 3;\n    if(wb->l+36 > fp->hdr->bufSize) if(flushBuffer(fp)) return 4;\n    lastChrom = chrom[0];\n    tid = bwGetTid(fp, chrom[0]);\n    if(tid == (uint32_t) -1) return 5;\n    if(tid != wb->tid) {\n        if(flushBuffer(fp)) return 6;\n        wb->tid = tid;\n        wb->start = start[0];\n        wb->end = end[0];\n    }\n\n    //Ensure that everything is set correctly\n    wb->ltype = 1;\n    if(wb->l <= 24) {\n        wb->start = start[0];\n        wb->span = 0;\n        wb->step = 0;\n    }\n    if(!memcpy((char*)wb->p+wb->l, start, sizeof(uint32_t))) return 7;\n    if(!memcpy((char*)wb->p+wb->l+4, end, sizeof(uint32_t))) return 8;\n    if(!memcpy((char*)wb->p+wb->l+8, values, sizeof(float))) return 9;\n    updateStats(fp, end[0]-start[0], values[0]);\n    wb->l += 12;\n\n    for(i=1; i<n; i++) {\n        if(strcmp(chrom[i],lastChrom) != 0) {\n            wb->end = end[i-1];\n            flushBuffer(fp);\n            lastChrom = chrom[i];\n            tid = bwGetTid(fp, chrom[i]);\n            if(tid == (uint32_t) -1) return 10;\n            wb->tid = tid;\n            wb->start = start[i];\n        }\n        if(wb->l+12 > fp->hdr->bufSize) { //12 bytes/entry\n            wb->end = end[i-1];\n            flushBuffer(fp);\n            wb->start = start[i];\n        }\n        if(!memcpy((char*)wb->p+wb->l, &(start[i]), sizeof(uint32_t))) return 11;\n        if(!memcpy((char*)wb->p+wb->l+4, &(end[i]), sizeof(uint32_t))) return 12;\n        if(!memcpy((char*)wb->p+wb->l+8, &(values[i]), sizeof(float))) return 13;\n        updateStats(fp, end[i]-start[i], values[i]);\n        wb->l += 12;\n    }\n    wb->end = end[i-1];\n\n    return 0;\n}\n\nint bwAppendIntervals(bigWigFile_t *fp, const uint32_t *start, const uint32_t *end, const float *values, uint32_t n) {\n    uint32_t i;\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    if(!n) return 0;\n    if(!fp->isWrite) return 1;\n    if(!wb) return 2;\n    if(wb->ltype != 1) return 3;\n\n    for(i=0; i<n; i++) {\n        if(wb->l+12 > fp->hdr->bufSize) {\n            if(i>0) { //otherwise it's already set\n                wb->end = end[i-1];\n            }\n            flushBuffer(fp);\n            wb->start = start[i];\n        }\n        if(!memcpy((char*)wb->p+wb->l, &(start[i]), sizeof(uint32_t))) return 4;\n        if(!memcpy((char*)wb->p+wb->l+4, &(end[i]), sizeof(uint32_t))) return 5;\n        if(!memcpy((char*)wb->p+wb->l+8, &(values[i]), sizeof(float))) return 6;\n        updateStats(fp, end[i]-start[i], values[i]);\n        wb->l += 12;\n    }\n    wb->end = end[i-1];\n\n    return 0;\n}\n\n//8 bytes per entry\nint bwAddIntervalSpans(bigWigFile_t *fp, const char *chrom, const uint32_t *start, uint32_t span, const float *values, uint32_t n) {\n    uint32_t i, tid;\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    if(!n) return 0;\n    if(!fp->isWrite) return 1;\n    if(!wb) return 2;\n    if(wb->ltype != 2) if(flushBuffer(fp)) return 3;\n    if(flushBuffer(fp)) return 4;\n\n    tid = bwGetTid(fp, chrom);\n    if(tid == (uint32_t) -1) return 5;\n    wb->tid = tid;\n    wb->start = start[0];\n    wb->step = 0;\n    wb->span = span;\n    wb->ltype = 2;\n\n    for(i=0; i<n; i++) {\n        if(wb->l + 8 >= fp->hdr->bufSize) { //8 bytes/entry\n            if(i) wb->end = start[i-1]+span;\n            flushBuffer(fp);\n            wb->start = start[i];\n        }\n        if(!memcpy((char*)wb->p+wb->l, &(start[i]), sizeof(uint32_t))) return 5;\n        if(!memcpy((char*)wb->p+wb->l+4, &(values[i]), sizeof(float))) return 6;\n        updateStats(fp, span, values[i]);\n        wb->l += 8;\n    }\n    wb->end = start[n-1] + span;\n\n    return 0;\n}\n\nint bwAppendIntervalSpans(bigWigFile_t *fp, const uint32_t *start, const float *values, uint32_t n) {\n    uint32_t i;\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    if(!n) return 0;\n    if(!fp->isWrite) return 1;\n    if(!wb) return 2;\n    if(wb->ltype != 2) return 3;\n\n    for(i=0; i<n; i++) {\n        if(wb->l + 8 >= fp->hdr->bufSize) {\n            if(i) wb->end = start[i-1]+wb->span;\n            flushBuffer(fp);\n            wb->start = start[i];\n        }\n        if(!memcpy((char*)wb->p+wb->l, &(start[i]), sizeof(uint32_t))) return 4;\n        if(!memcpy((char*)wb->p+wb->l+4, &(values[i]), sizeof(float))) return 5;\n        updateStats(fp, wb->span, values[i]);\n        wb->l += 8;\n    }\n    wb->end = start[n-1] + wb->span;\n\n    return 0;\n}\n\n//4 bytes per entry\nint bwAddIntervalSpanSteps(bigWigFile_t *fp, const char *chrom, uint32_t start, uint32_t span, uint32_t step, const float *values, uint32_t n) {\n    uint32_t i, tid;\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    if(!n) return 0;\n    if(!fp->isWrite) return 1;\n    if(!wb) return 2;\n    if(wb->ltype != 3) flushBuffer(fp);\n    if(flushBuffer(fp)) return 3;\n\n    tid = bwGetTid(fp, chrom);\n    if(tid == (uint32_t) -1) return 4;\n    wb->tid = tid;\n    wb->start = start;\n    wb->step = step;\n    wb->span = span;\n    wb->ltype = 3;\n\n    for(i=0; i<n; i++) {\n        if(wb->l + 4 >= fp->hdr->bufSize) {\n            wb->end = wb->start + ((wb->l-24)>>2) * step;\n            flushBuffer(fp);\n            wb->start = wb->end;\n        }\n        if(!memcpy((char*)wb->p+wb->l, &(values[i]), sizeof(float))) return 5;\n        updateStats(fp, wb->span, values[i]);\n        wb->l += 4;\n    }\n    wb->end = wb->start + (wb->l>>2) * step;\n\n    return 0;\n}\n\nint bwAppendIntervalSpanSteps(bigWigFile_t *fp, const float *values, uint32_t n) {\n    uint32_t i;\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    if(!n) return 0;\n    if(!fp->isWrite) return 1;\n    if(!wb) return 2;\n    if(wb->ltype != 3) return 3;\n\n    for(i=0; i<n; i++) {\n        if(wb->l + 4 >= fp->hdr->bufSize) {\n            wb->end = wb->start + ((wb->l-24)>>2) * wb->step;\n            flushBuffer(fp);\n            wb->start = wb->end;\n        }\n        if(!memcpy((char*)wb->p+wb->l, &(values[i]), sizeof(float))) return 4;\n        updateStats(fp, wb->span, values[i]);\n        wb->l += 4;\n    }\n    wb->end = wb->start + (wb->l>>2) * wb->step;\n\n    return 0;\n}\n\n//0 on success\nint writeSummary(bigWigFile_t *fp) {\n    if(writeAtPos(&(fp->hdr->nBasesCovered), sizeof(uint64_t), 1, fp->hdr->summaryOffset, fp->URL->x.fp)) return 1;\n    if(writeAtPos(&(fp->hdr->minVal), sizeof(double), 1, fp->hdr->summaryOffset+8, fp->URL->x.fp)) return 2;\n    if(writeAtPos(&(fp->hdr->maxVal), sizeof(double), 1, fp->hdr->summaryOffset+16, fp->URL->x.fp)) return 3;\n    if(writeAtPos(&(fp->hdr->sumData), sizeof(double), 1, fp->hdr->summaryOffset+24, fp->URL->x.fp)) return 4;\n    if(writeAtPos(&(fp->hdr->sumSquared), sizeof(double), 1, fp->hdr->summaryOffset+32, fp->URL->x.fp)) return 5;\n    return 0;\n}\n\nstatic bwRTreeNode_t *makeEmptyNode(uint32_t blockSize) {\n    bwRTreeNode_t *n = calloc(1, sizeof(bwRTreeNode_t));\n    if(!n) return NULL;\n\n    n->chrIdxStart = malloc(blockSize*sizeof(uint32_t));\n    if(!n->chrIdxStart) goto error;\n    n->baseStart = malloc(blockSize*sizeof(uint32_t));\n    if(!n->baseStart) goto error;\n    n->chrIdxEnd = malloc(blockSize*sizeof(uint32_t));\n    if(!n->chrIdxEnd) goto error;\n    n->baseEnd = malloc(blockSize*sizeof(uint32_t));\n    if(!n->baseEnd) goto error;\n    n->dataOffset = calloc(blockSize,sizeof(uint64_t)); //This MUST be 0 for node writing!\n    if(!n->dataOffset) goto error;\n    n->x.child = malloc(blockSize*sizeof(uint64_t));\n    if(!n->x.child) goto error;\n\n    return n;\n\nerror:\n    if(n->chrIdxStart) free(n->chrIdxStart);\n    if(n->baseStart) free(n->baseStart);\n    if(n->chrIdxEnd) free(n->chrIdxEnd);\n    if(n->baseEnd) free(n->baseEnd);\n    if(n->dataOffset) free(n->dataOffset);\n    if(n->x.child) free(n->x.child);\n    free(n);\n    return NULL;\n}\n\n//Returns 0 on success. This doesn't attempt to clean up!\nstatic bwRTreeNode_t *addLeaves(bwLL **ll, uint64_t *sz, uint64_t toProcess, uint32_t blockSize) {\n    uint32_t i;\n    uint64_t foo;\n    bwRTreeNode_t *n = makeEmptyNode(blockSize);\n    if(!n) return NULL;\n\n    if(toProcess <= blockSize) {\n        for(i=0; i<toProcess; i++) {\n            n->chrIdxStart[i] = (*ll)->node->chrIdxStart[0];\n            n->baseStart[i] = (*ll)->node->baseStart[0];\n            n->chrIdxEnd[i] = (*ll)->node->chrIdxEnd[(*ll)->node->nChildren-1];\n            n->baseEnd[i] = (*ll)->node->baseEnd[(*ll)->node->nChildren-1];\n            n->x.child[i] = (*ll)->node;\n            *sz += 4 + 32*(*ll)->node->nChildren;\n            *ll = (*ll)->next;\n            n->nChildren++;\n        }\n    } else {\n        for(i=0; i<blockSize; i++) {\n            foo = ceil(((double) toProcess)/((double) blockSize-i));\n            if(!ll) break;\n            n->x.child[i] = addLeaves(ll, sz, foo, blockSize);\n            if(!n->x.child[i]) goto error;\n            n->chrIdxStart[i] = n->x.child[i]->chrIdxStart[0];\n            n->baseStart[i] = n->x.child[i]->baseStart[0];\n            n->chrIdxEnd[i] = n->x.child[i]->chrIdxEnd[n->x.child[i]->nChildren-1];\n            n->baseEnd[i] = n->x.child[i]->baseEnd[n->x.child[i]->nChildren-1];\n            n->nChildren++;\n            toProcess -= foo;\n        }\n    }\n\n    *sz += 4 + 24*n->nChildren;\n    return n;\n\nerror:\n    bwDestroyIndexNode(n);\n    return NULL;\n}\n\n//Returns 1 on error\nint writeIndexTreeNode(FILE *fp, bwRTreeNode_t *n, uint8_t *wrote, int level) {\n    uint8_t one = 0;\n    uint32_t i, j, vector[6] = {0, 0, 0, 0, 0, 0}; //The last 8 bytes are left as 0\n\n    if(n->isLeaf) return 0;\n\n    for(i=0; i<n->nChildren; i++) {\n        if(n->dataOffset[i]) { //traverse into child\n            if(n->isLeaf) return 0; //Only write leaves once!\n            if(writeIndexTreeNode(fp, n->x.child[i], wrote, level+1)) return 1;\n        } else {\n            n->dataOffset[i] = ftell(fp);\n            if(fwrite(&(n->x.child[i]->isLeaf), sizeof(uint8_t), 1, fp) != 1) return 1;\n            if(fwrite(&one, sizeof(uint8_t), 1, fp) != 1) return 1; //one byte of padding\n            if(fwrite(&(n->x.child[i]->nChildren), sizeof(uint16_t), 1, fp) != 1) return 1;\n            for(j=0; j<n->x.child[i]->nChildren; j++) {\n                vector[0] = n->x.child[i]->chrIdxStart[j];\n                vector[1] = n->x.child[i]->baseStart[j];\n                vector[2] = n->x.child[i]->chrIdxEnd[j];\n                vector[3] = n->x.child[i]->baseEnd[j];\n                if(n->x.child[i]->isLeaf) {\n                    //Include the offset and size\n                    if(fwrite(vector, sizeof(uint32_t), 4, fp) != 4) return 1;\n                    if(fwrite(&(n->x.child[i]->dataOffset[j]), sizeof(uint64_t), 1, fp) != 1) return 1;\n                    if(fwrite(&(n->x.child[i]->x.size[j]), sizeof(uint64_t), 1, fp) != 1) return 1;\n                } else {\n                    if(fwrite(vector, sizeof(uint32_t), 6, fp) != 6) return 1;\n                }\n            }\n            *wrote = 1;\n        }\n    }\n\n    return 0;\n}\n\n//returns 1 on success\nint writeIndexOffsets(FILE *fp, bwRTreeNode_t *n, uint64_t offset) {\n    uint32_t i;\n\n    if(n->isLeaf) return 0;\n    for(i=0; i<n->nChildren; i++) {\n        if(writeIndexOffsets(fp, n->x.child[i], n->dataOffset[i])) return 1;\n        if(writeAtPos(&(n->dataOffset[i]), sizeof(uint64_t), 1, offset+20+24*i, fp)) return 2;\n    }\n    return 0;\n}\n\n//Returns 0 on success\nint writeIndexTree(bigWigFile_t *fp) {\n    uint64_t offset;\n    uint8_t wrote = 0;\n    int rv;\n\n    while((rv = writeIndexTreeNode(fp->URL->x.fp, fp->idx->root, &wrote, 0)) == 0) {\n        if(!wrote) break;\n        wrote = 0;\n    }\n\n    if(rv || wrote) return 1;\n\n    //Save the file position\n    offset = bwTell(fp);\n\n    //Write the offsets\n    if(writeIndexOffsets(fp->URL->x.fp, fp->idx->root, fp->idx->rootOffset)) return 2;\n\n    //Move the file pointer back to the end\n    bwSetPos(fp, offset);\n\n    return 0;\n}\n\n//Returns 0 on success. The original state SHOULD be preserved on error\nint writeIndex(bigWigFile_t *fp) {\n    uint32_t four = IDX_MAGIC;\n    uint64_t idxSize = 0, foo;\n    uint8_t one = 0;\n    uint32_t i, vector[6] = {0, 0, 0, 0, 0, 0}; //The last 8 bytes are left as 0\n    bwLL *ll = fp->writeBuffer->firstIndexNode, *p;\n    bwRTreeNode_t *root = NULL;\n\n    if(!fp->writeBuffer->nBlocks) return 0;\n    fp->idx = malloc(sizeof(bwRTree_t));\n    if(!fp->idx) return 2;\n    fp->idx->root = root;\n\n    //Update the file header to indicate the proper index position\n    foo = bwTell(fp);\n    if(writeAtPos(&foo, sizeof(uint64_t), 1, 0x18, fp->URL->x.fp)) return 3;\n\n    //Make the tree\n    if(ll == fp->writeBuffer->currentIndexNode) {\n        root = ll->node;\n        idxSize = 4 + 24*root->nChildren;\n    } else {\n        root = addLeaves(&ll, &idxSize, ceil(((double)fp->writeBuffer->nBlocks)/fp->writeBuffer->blockSize), fp->writeBuffer->blockSize);\n    }\n    if(!root) return 4;\n    fp->idx->root = root;\n\n    ll = fp->writeBuffer->firstIndexNode;\n    while(ll) {\n        p = ll->next;\n        free(ll);\n        ll=p;\n    }\n\n    //write the header\n    if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 5;\n    if(fwrite(&(fp->writeBuffer->blockSize), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 6;\n    if(fwrite(&(fp->writeBuffer->nBlocks), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 7;\n    if(fwrite(&(root->chrIdxStart[0]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 8;\n    if(fwrite(&(root->baseStart[0]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 9;\n    if(fwrite(&(root->chrIdxEnd[root->nChildren-1]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 10;\n    if(fwrite(&(root->baseEnd[root->nChildren-1]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 11;\n    if(fwrite(&idxSize, sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 12;\n    four = 1;\n    if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 13;\n    four = 0;\n    if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 14; //padding\n    fp->idx->rootOffset = bwTell(fp);\n\n    //Write the root node, since writeIndexTree writes the children and fills in the offset\n    if(fwrite(&(root->isLeaf), sizeof(uint8_t), 1, fp->URL->x.fp) != 1) return 16;\n    if(fwrite(&one, sizeof(uint8_t), 1, fp->URL->x.fp) != 1) return 17; //one byte of padding\n    if(fwrite(&(root->nChildren), sizeof(uint16_t), 1, fp->URL->x.fp) != 1) return 18;\n    for(i=0; i<root->nChildren; i++) {\n        vector[0] = root->chrIdxStart[i];\n        vector[1] = root->baseStart[i];\n        vector[2] = root->chrIdxEnd[i];\n        vector[3] = root->baseEnd[i];\n        if(root->isLeaf) {\n            //Include the offset and size\n            if(fwrite(vector, sizeof(uint32_t), 4, fp->URL->x.fp) != 4) return 19;\n            if(fwrite(&(root->dataOffset[i]), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 20;\n            if(fwrite(&(root->x.size[i]), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 21;\n        } else {\n            root->dataOffset[i] = 0; //FIXME: Something upstream is setting this to impossible values (e.g., 0x21?!?!?)\n            if(fwrite(vector, sizeof(uint32_t), 6, fp->URL->x.fp) != 6) return 22;\n        }\n    }\n\n    //Write each level\n    if(writeIndexTree(fp)) return 23;\n\n    return 0;\n}\n\n//The first zoom level has a resolution of 4x mean entry size\n//This may or may not produce the requested number of zoom levels\nint makeZoomLevels(bigWigFile_t *fp) {\n    uint32_t meanBinSize, i;\n    uint32_t multiplier = 4, zoom = 10, maxZoom = 0;\n    uint16_t nLevels = 0;\n\n    meanBinSize = ((double) fp->writeBuffer->runningWidthSum)/(fp->writeBuffer->nEntries);\n    //In reality, one level is skipped\n    meanBinSize *= 4;\n    //N.B., we must ALWAYS check that the zoom doesn't overflow a uint32_t!\n    if(((uint32_t)-1)>>2 < meanBinSize) return 0; //No zoom levels!\n    if(meanBinSize*4 > zoom) zoom = multiplier*meanBinSize;\n\n    fp->hdr->zoomHdrs = calloc(1, sizeof(bwZoomHdr_t));\n    if(!fp->hdr->zoomHdrs) return 1;\n    fp->hdr->zoomHdrs->level = malloc(fp->hdr->nLevels * sizeof(uint32_t));\n    fp->hdr->zoomHdrs->dataOffset = calloc(fp->hdr->nLevels, sizeof(uint64_t));\n    fp->hdr->zoomHdrs->indexOffset = calloc(fp->hdr->nLevels, sizeof(uint64_t));\n    fp->hdr->zoomHdrs->idx = calloc(fp->hdr->nLevels, sizeof(bwRTree_t*));\n    if(!fp->hdr->zoomHdrs->level) return 2;\n    if(!fp->hdr->zoomHdrs->dataOffset) return 3;\n    if(!fp->hdr->zoomHdrs->indexOffset) return 4;\n    if(!fp->hdr->zoomHdrs->idx) return 5;\n\n    //There's no point in having a zoom level larger than the largest chromosome\n    //This will none the less allow at least one zoom level, which is generally needed for IGV et al.\n    for(i=0; i<fp->cl->nKeys; i++) {\n        if(fp->cl->len[i] > maxZoom) maxZoom = fp->cl->len[i];\n    }\n    if(zoom > maxZoom) zoom = maxZoom;\n\n    for(i=0; i<fp->hdr->nLevels; i++) {\n        if(zoom > maxZoom) break; //prevent absurdly large zoom levels\n        fp->hdr->zoomHdrs->level[i] = zoom;\n        nLevels++;\n        if(((uint32_t)-1)/multiplier < zoom) break;\n        zoom *= multiplier;\n    }\n    fp->hdr->nLevels = nLevels;\n\n    fp->writeBuffer->firstZoomBuffer = calloc(nLevels,sizeof(bwZoomBuffer_t*));\n    if(!fp->writeBuffer->firstZoomBuffer) goto error;\n    fp->writeBuffer->lastZoomBuffer = calloc(nLevels,sizeof(bwZoomBuffer_t*));\n    if(!fp->writeBuffer->lastZoomBuffer) goto error;\n    fp->writeBuffer->nNodes = calloc(nLevels, sizeof(uint64_t));\n\n    for(i=0; i<fp->hdr->nLevels; i++) {\n        fp->writeBuffer->firstZoomBuffer[i] = calloc(1, sizeof(bwZoomBuffer_t));\n        if(!fp->writeBuffer->firstZoomBuffer[i]) goto error;\n        fp->writeBuffer->firstZoomBuffer[i]->p = calloc(fp->hdr->bufSize/32, 32);\n        if(!fp->writeBuffer->firstZoomBuffer[i]->p) goto error;\n        fp->writeBuffer->firstZoomBuffer[i]->m = fp->hdr->bufSize;\n        ((uint32_t*)fp->writeBuffer->firstZoomBuffer[i]->p)[0] = 0;\n        ((uint32_t*)fp->writeBuffer->firstZoomBuffer[i]->p)[1] = 0;\n        ((uint32_t*)fp->writeBuffer->firstZoomBuffer[i]->p)[2] = fp->hdr->zoomHdrs->level[i];\n        if(fp->hdr->zoomHdrs->level[i] > fp->cl->len[0]) ((uint32_t*)fp->writeBuffer->firstZoomBuffer[i]->p)[2] = fp->cl->len[0];\n        fp->writeBuffer->lastZoomBuffer[i] =  fp->writeBuffer->firstZoomBuffer[i];\n    }\n\n    return 0;\n\nerror:\n    if(fp->writeBuffer->firstZoomBuffer) {\n        for(i=0; i<fp->hdr->nLevels; i++) {\n            if(fp->writeBuffer->firstZoomBuffer[i]) {\n                if(fp->writeBuffer->firstZoomBuffer[i]->p) free(fp->writeBuffer->firstZoomBuffer[i]->p);\n                free(fp->writeBuffer->firstZoomBuffer[i]);\n            }\n        }\n        free(fp->writeBuffer->firstZoomBuffer);\n    }\n    if(fp->writeBuffer->lastZoomBuffer) free(fp->writeBuffer->lastZoomBuffer);\n    if(fp->writeBuffer->nNodes) free(fp->writeBuffer->lastZoomBuffer);\n    return 6;\n}\n\n//Given an interval start, calculate the next one at a zoom level\nvoid nextPos(bigWigFile_t *fp, uint32_t size, uint32_t *pos, uint32_t desiredTid) {\n    uint32_t *tid = pos;\n    uint32_t *start = pos+1;\n    uint32_t *end = pos+2;\n    *start += size;\n    if(*start >= fp->cl->len[*tid]) {\n        (*start) = 0;\n        (*tid)++;\n    }\n\n    //prevent needless iteration when changing chromosomes\n    if(*tid < desiredTid) {\n        *tid = desiredTid;\n        *start = 0;\n    }\n\n    (*end) = *start+size;\n    if(*end > fp->cl->len[*tid]) (*end) = fp->cl->len[*tid];\n}\n\n//Return the number of bases two intervals overlap\nuint32_t overlapsInterval(uint32_t tid0, uint32_t start0, uint32_t end0, uint32_t tid1, uint32_t start1, uint32_t end1) {\n    if(tid0 != tid1) return 0;\n    if(end0 <= start1) return 0;\n    if(end1 <= start0) return 0;\n    if(end0 <= end1) {\n        if(start1 > start0) return end0-start1;\n        return end0-start0;\n    } else {\n        if(start1 > start0) return end1-start1;\n        return end1-start0;\n    }\n}\n\n//Returns the number of bases of the interval written\nuint32_t updateInterval(bigWigFile_t *fp, bwZoomBuffer_t *buffer, double *sum, double *sumsq, uint32_t size, uint32_t tid, uint32_t start, uint32_t end, float value) {\n    uint32_t *p2 = (uint32_t*) buffer->p;\n    float *fp2 = (float*) p2;\n    uint32_t rv = 0, offset = 0;\n    if(!buffer) return 0;\n    if(buffer->l+32 >= buffer->m) return 0;\n\n    //Make sure that we don't overflow a uint32_t by adding some huge value to start\n    if(start + size < start) size = ((uint32_t) -1) - start;\n\n    if(buffer->l) {\n        offset = buffer->l/32;\n    } else {\n        p2[0] = tid;\n        p2[1] = start;\n        if(start+size < end) p2[2] = start+size;\n        else p2[2] = end;\n    }\n\n    //Do we have any overlap with the previously added interval?\n    if(offset) {\n        rv = overlapsInterval(p2[8*(offset-1)], p2[8*(offset-1)+1], p2[8*(offset-1)+1] + size, tid, start, end);\n        if(rv) {\n            p2[8*(offset-1)+2] = start + rv;\n            p2[8*(offset-1)+3] += rv;\n            if(fp2[8*(offset-1)+4] > value) fp2[8*(offset-1)+4] = value;\n            if(fp2[8*(offset-1)+5] < value) fp2[8*(offset-1)+5] = value;\n            *sum += rv*value;\n            *sumsq += rv*pow(value, 2.0);\n            return rv;\n        } else {\n            fp2[8*(offset-1)+6] = *sum;\n            fp2[8*(offset-1)+7] = *sumsq;\n            *sum = 0.0;\n            *sumsq = 0.0;\n        }\n    }\n\n    //If we move to a new interval then skip iterating over a bunch of obviously non-overlapping intervals\n    if(offset && p2[8*offset+2] == 0) {\n        p2[8*offset] = tid;\n        p2[8*offset+1] = start;\n        if(start+size < end) p2[8*offset+2] = start+size;\n        else p2[8*offset+2] = end;\n        //nextPos(fp, size, p2+8*offset, tid); //We can actually skip uncovered intervals\n    }\n\n    //Add a new entry\n    while(!(rv = overlapsInterval(p2[8*offset], p2[8*offset+1], p2[8*offset+1] + size, tid, start, end))) {\n        p2[8*offset] = tid;\n        p2[8*offset+1] = start;\n        if(start+size < end) p2[8*offset+2] = start+size;\n        else p2[8*offset+2] = end;\n        //nextPos(fp, size, p2+8*offset, tid);\n    }\n    p2[8*offset+3] = rv;\n    fp2[8*offset+4] = value; //min\n    fp2[8*offset+5] = value; //max\n    *sum += rv * value;\n    *sumsq += rv * pow(value,2.0);\n    buffer->l += 32;\n    return rv;\n}\n\n//Returns 0 on success\nint addIntervalValue(bigWigFile_t *fp, uint64_t *nEntries, double *sum, double *sumsq, bwZoomBuffer_t *buffer, uint32_t itemsPerSlot, uint32_t zoom, uint32_t tid, uint32_t start, uint32_t end, float value) {\n    bwZoomBuffer_t *newBuffer = NULL;\n    uint32_t rv;\n\n    while(start < end) {\n        rv = updateInterval(fp, buffer, sum, sumsq, zoom, tid, start, end, value);\n        if(!rv) {\n            //Allocate a new buffer\n            newBuffer = calloc(1, sizeof(bwZoomBuffer_t));\n            if(!newBuffer) return 1;\n            newBuffer->p = calloc(itemsPerSlot, 32);\n            if(!newBuffer->p) goto error;\n            newBuffer->m = itemsPerSlot*32;\n            memcpy(newBuffer->p, (unsigned char*)buffer->p+buffer->l-32, 4);\n            memcpy((unsigned char*)newBuffer->p+4, (unsigned char*)buffer->p + buffer->l-28, 4);\n            ((uint32_t*) newBuffer->p)[2] = ((uint32_t*) newBuffer->p)[1] + zoom;\n            *sum = *sumsq = 0.0;\n            rv = updateInterval(fp, newBuffer, sum, sumsq, zoom, tid, start, end, value);\n            if(!rv) goto error;\n            buffer->next = newBuffer;\n            buffer = buffer->next;\n            *nEntries += 1;\n        }\n        start += rv;\n    }\n\n    return 0;\n\nerror:\n    if(newBuffer) {\n        if(newBuffer->m) free(newBuffer->p);\n        free(newBuffer);\n    }\n    return 2;\n}\n\n//Get all of the intervals and add them to the appropriate zoomBuffer\nint constructZoomLevels(bigWigFile_t *fp) {\n    bwOverlapIterator_t *it = NULL;\n    double *sum = NULL, *sumsq = NULL;\n    uint32_t i, j, k;\n\n    sum = calloc(fp->hdr->nLevels, sizeof(double));\n    sumsq = calloc(fp->hdr->nLevels, sizeof(double));\n    if(!sum || !sumsq) goto error;\n\n    for(i=0; i<fp->cl->nKeys; i++) {\n        it = bwOverlappingIntervalsIterator(fp, fp->cl->chrom[i], 0, fp->cl->len[i], 100000);\n        if(!it) goto error;\n\twhile(it->data != NULL){\n\t  for(j=0;j<it->intervals->l;j++){\n\t\tfor(k=0;k<fp->hdr->nLevels;k++){\n\t\t\tif(addIntervalValue(fp, &(fp->writeBuffer->nNodes[k]), sum+k, sumsq+k, fp->writeBuffer->lastZoomBuffer[k], fp->hdr->bufSize/32, fp->hdr->zoomHdrs->level[k], i, it->intervals->start[j], it->intervals->end[j], it->intervals->value[j])) goto error;\n\t\t\twhile(fp->writeBuffer->lastZoomBuffer[k]->next) fp->writeBuffer->lastZoomBuffer[k] = fp->writeBuffer->lastZoomBuffer[k]->next;\n\t\t}\n\t  }\n\t  it = bwIteratorNext(it);\n\t}\n\tbwIteratorDestroy(it);\n\n    }\n\n    //Make an index for each zoom level\n    for(i=0; i<fp->hdr->nLevels; i++) {\n        fp->hdr->zoomHdrs->idx[i] = calloc(1, sizeof(bwRTree_t));\n        if(!fp->hdr->zoomHdrs->idx[i]) return 1;\n        fp->hdr->zoomHdrs->idx[i]->blockSize = fp->writeBuffer->blockSize;\n    }\n\n\n    free(sum);\n    free(sumsq);\n\n    return 0;\n\nerror:\n    if(it) bwIteratorDestroy(it);\n    if(sum) free(sum);\n    if(sumsq) free(sumsq);\n    return 1;\n}\n\nint writeZoomLevels(bigWigFile_t *fp) {\n    uint64_t offset1, offset2, idxSize = 0;\n    uint32_t i, j, four = 0, last, vector[6] = {0, 0, 0, 0, 0, 0}; //The last 8 bytes are left as 0;\n    uint8_t wrote, one = 0;\n    uint16_t actualNLevels = 0;\n    int rv;\n    bwLL *ll, *p;\n    bwRTreeNode_t *root;\n    bwZoomBuffer_t *zb, *zb2;\n    bwWriteBuffer_t *wb = fp->writeBuffer;\n    uLongf sz;\n\n    for(i=0; i<fp->hdr->nLevels; i++) {\n        if(i) {\n            //Is this a duplicate level?\n            if(fp->writeBuffer->nNodes[i] == fp->writeBuffer->nNodes[i-1]) break;\n        }\n        actualNLevels++;\n\n        //reserve a uint32_t for the number of blocks\n        fp->hdr->zoomHdrs->dataOffset[i] = bwTell(fp);\n        fp->writeBuffer->nBlocks = 0;\n        fp->writeBuffer->l = 24;\n        if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 1;\n        zb = fp->writeBuffer->firstZoomBuffer[i];\n        fp->writeBuffer->firstIndexNode = NULL;\n        fp->writeBuffer->currentIndexNode = NULL;\n        while(zb) {\n            sz = fp->hdr->bufSize;\n            if(compress(wb->compressP, &sz, zb->p, zb->l) != Z_OK) return 2;\n\n            //write the data to disk\n            if(fwrite(wb->compressP, sizeof(uint8_t), sz, fp->URL->x.fp) != sz) return 3;\n\n            //Add an entry into the index\n            last = (zb->l - 32)>>2;\n            if(addIndexEntry(fp, ((uint32_t*)zb->p)[0], ((uint32_t*)zb->p)[last], ((uint32_t*)zb->p)[1], ((uint32_t*)zb->p)[last+2], bwTell(fp)-sz, sz)) return 4;\n\n            wb->nBlocks++;\n            wb->l = 24;\n            zb = zb->next;\n        }\n        if(writeAtPos(&(wb->nBlocks), sizeof(uint32_t), 1, fp->hdr->zoomHdrs->dataOffset[i], fp->URL->x.fp)) return 5;\n\n        //Make the tree\n        ll = fp->writeBuffer->firstIndexNode;\n        if(ll == fp->writeBuffer->currentIndexNode) {\n            root = ll->node;\n            idxSize = 4 + 24*root->nChildren;\n        } else {\n            root = addLeaves(&ll, &idxSize, ceil(((double)fp->writeBuffer->nBlocks)/fp->writeBuffer->blockSize), fp->writeBuffer->blockSize);\n        }\n        if(!root) return 4;\n        fp->hdr->zoomHdrs->idx[i]->root = root;\n\n        ll = fp->writeBuffer->firstIndexNode;\n        while(ll) {\n            p = ll->next;\n            free(ll);\n            ll=p;\n        }\n\n\n        //write the index\n        wrote = 0;\n        fp->hdr->zoomHdrs->indexOffset[i] = bwTell(fp);\n        four = IDX_MAGIC;\n        if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 1;\n        root = fp->hdr->zoomHdrs->idx[i]->root;\n        if(fwrite(&(fp->writeBuffer->blockSize), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 6;\n        if(fwrite(&(fp->writeBuffer->nBlocks), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 7;\n        if(fwrite(&(root->chrIdxStart[0]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 8;\n        if(fwrite(&(root->baseStart[0]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 9;\n        if(fwrite(&(root->chrIdxEnd[root->nChildren-1]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 10;\n        if(fwrite(&(root->baseEnd[root->nChildren-1]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 11;\n        if(fwrite(&idxSize, sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 12;\n        four = fp->hdr->bufSize/32;\n        if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 13;\n        four = 0;\n        if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 14; //padding\n        fp->hdr->zoomHdrs->idx[i]->rootOffset = bwTell(fp);\n\n        //Write the root node, since writeIndexTree writes the children and fills in the offset\n        offset1 = bwTell(fp);\n        if(fwrite(&(root->isLeaf), sizeof(uint8_t), 1, fp->URL->x.fp) != 1) return 16;\n        if(fwrite(&one, sizeof(uint8_t), 1, fp->URL->x.fp) != 1) return 17; //one byte of padding\n        if(fwrite(&(root->nChildren), sizeof(uint16_t), 1, fp->URL->x.fp) != 1) return 18;\n        for(j=0; j<root->nChildren; j++) {\n            vector[0] = root->chrIdxStart[j];\n            vector[1] = root->baseStart[j];\n            vector[2] = root->chrIdxEnd[j];\n            vector[3] = root->baseEnd[j];\n            if(root->isLeaf) {\n                //Include the offset and size\n                if(fwrite(vector, sizeof(uint32_t), 4, fp->URL->x.fp) != 4) return 19;\n                if(fwrite(&(root->dataOffset[j]), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 20;\n                if(fwrite(&(root->x.size[j]), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 21;\n            } else {\n                if(fwrite(vector, sizeof(uint32_t), 6, fp->URL->x.fp) != 6) return 22;\n            }\n        }\n\n        while((rv = writeIndexTreeNode(fp->URL->x.fp, fp->hdr->zoomHdrs->idx[i]->root, &wrote, 0)) == 0) {\n            if(!wrote) break;\n            wrote = 0;\n        }\n\n        if(rv || wrote) return 6;\n\n        //Save the file position\n        offset2 = bwTell(fp);\n\n        //Write the offsets\n        if(writeIndexOffsets(fp->URL->x.fp, root, offset1)) return 2;\n\n        //Move the file pointer back to the end\n        bwSetPos(fp, offset2);\n\n\n        //Free the linked list\n        zb = fp->writeBuffer->firstZoomBuffer[i];\n        while(zb) {\n            if(zb->p) free(zb->p);\n            zb2 = zb->next;\n            free(zb);\n            zb = zb2;\n        }\n        fp->writeBuffer->firstZoomBuffer[i] = NULL;\n    }\n\n    //Free unused zoom levels\n    for(i=actualNLevels; i<fp->hdr->nLevels; i++) {\n        zb = fp->writeBuffer->firstZoomBuffer[i];\n        while(zb) {\n            if(zb->p) free(zb->p);\n            zb2 = zb->next;\n            free(zb);\n            zb = zb2;\n        }\n        fp->writeBuffer->firstZoomBuffer[i] = NULL;\n    }\n\n    //Write the zoom headers to disk\n    offset1 = bwTell(fp);\n    if(bwSetPos(fp, 0x40)) return 7;\n    four = 0;\n    for(i=0; i<actualNLevels; i++) {\n        if(fwrite(&(fp->hdr->zoomHdrs->level[i]), sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 8;\n        if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 9;\n        if(fwrite(&(fp->hdr->zoomHdrs->dataOffset[i]), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 10;\n        if(fwrite(&(fp->hdr->zoomHdrs->indexOffset[i]), sizeof(uint64_t), 1, fp->URL->x.fp) != 1) return 11;\n    }\n\n    //Write the number of levels if needed\n    if(bwSetPos(fp, 0x6)) return 12;\n    if(fwrite(&actualNLevels, sizeof(uint16_t), 1, fp->URL->x.fp) != 1) return 13;\n\n    if(bwSetPos(fp, offset1)) return 14;\n\n    return 0;\n}\n\n//0 on success\nint bwFinalize(bigWigFile_t *fp) {\n    uint32_t four;\n    uint64_t offset;\n    if(!fp->isWrite) return 0;\n\n    //Flush the buffer\n    if(flushBuffer(fp)) return 1; //Valgrind reports a problem here!\n\n    //Update the data section with the number of blocks written\n    if(fp->hdr) {\n        if(writeAtPos(&(fp->writeBuffer->nBlocks), sizeof(uint64_t), 1, fp->hdr->dataOffset, fp->URL->x.fp)) return 2;\n    } else {\n        //The header wasn't written!\n        return 1;\n    }\n\n    //write the bufferSize\n    if(fp->hdr->bufSize) {\n        if(writeAtPos(&(fp->hdr->bufSize), sizeof(uint32_t), 1, 0x34, fp->URL->x.fp)) return 2;\n    }\n\n    //write the summary information\n    if(writeSummary(fp)) return 3;\n\n    //Convert the linked-list to a tree and write to disk\n    if(writeIndex(fp)) return 4;\n\n    //Zoom level stuff here?\n    if(fp->hdr->nLevels && fp->writeBuffer->nBlocks) {\n        offset = bwTell(fp);\n        if(makeZoomLevels(fp)) return 5;\n        if(constructZoomLevels(fp)) return 6;\n        bwSetPos(fp, offset);\n        if(writeZoomLevels(fp)) return 7; //This write nLevels as well\n    }\n\n    //write magic at the end of the file\n    four = BIGWIG_MAGIC;\n    if(fwrite(&four, sizeof(uint32_t), 1, fp->URL->x.fp) != 1) return 9;\n\n    return 0;\n}\n\n/*\ndata chunk:\nuint64_t number of blocks (2 / 110851)\nsome blocks\n\nan uncompressed data block (24 byte header)\nuint32_t Tid\t0-4\nuint32_t start\t4-8\nuint32_t end\t8-12\nuint32_t step\t12-16\nuint32_t span\t16-20\nuint8_t type\t20\nuint8_t padding\nuint16_t nItems\t22\nnItems of:\n    type 1: //12 bytes\n        uint32_t start\n        uint32_t end\n        float value\n    type 2: //8 bytes\n        uint32_t start\n        float value\n    type 3: //4 bytes\n        float value\n\ndata block index header\nuint32_t magic\nuint32_t blockSize (256 in the example) maximum number of children\nuint64_t number of blocks (2 / 110851)\nuint32_t startTid\nuint32_t startPos\nuint32_t endTid\nuint32_t endPos\nuint64_t index size? (0x1E7 / 0x1AF0401F) index address?\nuint32_t itemsPerBlock (1 / 1) 1024 for zoom headers 1024 for zoom headers\nuint32_t padding\n\ndata block index node non-leaf (4 bytes + 24*nChildren)\nuint8_t isLeaf\nuint8_t padding\nuint16_t nChildren (2, 256)\nuint32_t startTid\nuint32_t startPos\nuint32_t endTid\nuint32_t endPos\nuint64_t dataOffset (0x1AF05853, 0x1AF07057)\n\ndata block index node leaf (4 bytes + 32*nChildren)\nuint8_t isLeaf\nuint8_t padding\nuint16_t nChildren (2)\nuint32_t startTid\nuint32_t startPos\nuint32_t endTid\nuint32_t endPos\nuint64_t dataOffset (0x198, 0x1CF)\nuint64_t dataSize (55, 24)\n\nzoom data block\nuint32_t number of blocks (10519766)\nsome data blocks\n*/\n"
  },
  {
    "path": "libBigWig/io.c",
    "content": "#ifndef NOCURL\n#include <curl/curl.h>\n#endif\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#include \"bigWigIO.h\"\n#include <inttypes.h>\n#include <errno.h>\n\nsize_t GLOBAL_DEFAULTBUFFERSIZE;\n\n#ifndef NOCURL\nuint64_t getContentLength(const URL_t *URL) {\n    double size;\n    if(curl_easy_getinfo(URL->x.curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size) != CURLE_OK) {\n        return 0;\n    }\n    if(size== -1.0) return 0;\n    return (uint64_t) size;\n}\n\n//Fill the buffer, note that URL may be left in an unusable state on error!\nCURLcode urlFetchData(URL_t *URL, unsigned long bufSize) {\n    CURLcode rv;\n    char range[1024];\n\n    if(URL->filePos != (size_t) -1) URL->filePos += URL->bufLen;\n    else URL->filePos = 0;\n\n    URL->bufPos = URL->bufLen = 0; //Otherwise, we can't copy anything into the buffer!\n    sprintf(range,\"%lu-%lu\", URL->filePos, URL->filePos+bufSize-1);\n    rv = curl_easy_setopt(URL->x.curl, CURLOPT_RANGE, range);\n    if(rv != CURLE_OK) {\n        fprintf(stderr, \"[urlFetchData] Couldn't set the range (%s)\\n\", range);\n        return rv;\n    }\n\n    rv = curl_easy_perform(URL->x.curl);\n    errno = 0; //Sometimes curl_easy_perform leaves a random errno remnant\n    return rv;\n}\n\n//Read data into a buffer, ideally from a buffer already in memory\n//The loop is likely no longer needed.\nsize_t url_fread(void *obuf, size_t obufSize, URL_t *URL) {\n    size_t remaining = obufSize, fetchSize;\n    void *p = obuf;\n    CURLcode rv;\n\n    while(remaining) {\n        if(!URL->bufLen) {\n            rv = urlFetchData(URL, URL->bufSize);\n            if(rv != CURLE_OK) {\n                fprintf(stderr, \"[url_fread] urlFetchData (A) returned %s\\n\", curl_easy_strerror(rv));\n                return 0;\n            }  \n        } else if(URL->bufLen < URL->bufPos + remaining) { //Copy the remaining buffer and reload the buffer as needed\n            p = memcpy(p, URL->memBuf+URL->bufPos, URL->bufLen - URL->bufPos);\n            if(!p) return 0;\n            p += URL->bufLen - URL->bufPos;\n            remaining -= URL->bufLen - URL->bufPos;\n            if(remaining) {\n                if(!URL->isCompressed) {\n                    fetchSize = URL->bufSize;\n                } else {\n                    fetchSize = (remaining<URL->bufSize)?remaining:URL->bufSize;\n                }\n                rv = urlFetchData(URL, fetchSize);\n                if(rv != CURLE_OK) {\n                    fprintf(stderr, \"[url_fread] urlFetchData (B) returned %s\\n\", curl_easy_strerror(rv));\n                    return 0;\n                }\n            }\n        } else {\n            p = memcpy(p, URL->memBuf+URL->bufPos, remaining);\n            if(!p) return 0;\n            URL->bufPos += remaining;\n            remaining = 0;\n        }\n    }\n    return obufSize;\n}\n#endif\n\n//Returns the number of bytes requested or a smaller number on error\n//Note that in the case of remote files, the actual amount read may be less than the return value!\nsize_t urlRead(URL_t *URL, void *buf, size_t bufSize) {\n#ifndef NOCURL\n    if(URL->type==0) {\n        return fread(buf, bufSize, 1, URL->x.fp)*bufSize;\n    } else {\n        return url_fread(buf, bufSize, URL);\n    }\n#else\n    return fread(buf, bufSize, 1, URL->x.fp)*bufSize;\n#endif\n}\n\nsize_t bwFillBuffer(const void *inBuf, size_t l, size_t nmemb, void *pURL) {\n    URL_t *URL = (URL_t*) pURL;\n    void *p = URL->memBuf;\n    size_t copied = l*nmemb;\n    if(!p) return 0;\n\n    p += URL->bufLen;\n    if(l*nmemb > URL->bufSize - URL->bufPos) { //We received more than we can store!\n        copied = URL->bufSize - URL->bufLen;\n    }\n    memcpy(p, inBuf, copied);\n    URL->bufLen += copied;\n\n    if(!URL->memBuf) return 0; //signal error\n    return copied;\n}\n\n//Seek to an arbitrary location, returning a CURLcode\n//Note that a local file returns CURLE_OK on success or CURLE_FAILED_INIT on any error;\nCURLcode urlSeek(URL_t *URL, size_t pos) {\n#ifndef NOCURL\n    char range[1024];\n    CURLcode rv;\n\n    if(URL->type == BWG_FILE) {\n#endif\n        if(fseek(URL->x.fp, pos, SEEK_SET) == 0) {\n            errno = 0;\n            return CURLE_OK;\n        } else {\n            return CURLE_FAILED_INIT; //This is arbitrary\n        }\n#ifndef NOCURL\n    } else {\n        //If the location is covered by the buffer then don't seek!\n        if(pos < URL->filePos || pos >= URL->filePos+URL->bufLen) {\n            URL->filePos = pos;\n            URL->bufLen = 0; //Otherwise, filePos will get incremented on the next read!\n            URL->bufPos = 0;\n            //Maybe this works for FTP?\n            sprintf(range,\"%lu-%lu\", pos, pos+URL->bufSize-1);\n            rv = curl_easy_setopt(URL->x.curl, CURLOPT_RANGE, range);\n            if(rv != CURLE_OK) {\n                fprintf(stderr, \"[urlSeek] Couldn't set the range (%s)\\n\", range);\n                return rv;\n            }\n            rv = curl_easy_perform(URL->x.curl);\n            if(rv != CURLE_OK) {\n                fprintf(stderr, \"[urlSeek] curl_easy_perform received an error!\\n\");\n            }\n            errno = 0;  //Don't propogate remnant resolved libCurl errors\n            return rv;\n        } else {\n            URL->bufPos = pos-URL->filePos;\n            return CURLE_OK;\n        }\n    }\n#endif\n}\n\nURL_t *urlOpen(const char *fname, CURLcode (*callBack)(CURL*), const char *mode) {\n    URL_t *URL = calloc(1, sizeof(URL_t));\n    if(!URL) return NULL;\n    char *url = NULL, *req = NULL;\n#ifndef NOCURL\n    CURLcode code;\n    char range[1024];\n#endif\n\n    URL->fname = fname;\n\n    if((!mode) || (strchr(mode, 'w') == 0)) {\n        //Set the protocol\n#ifndef NOCURL\n        if(strncmp(fname, \"http://\", 7) == 0) URL->type = BWG_HTTP;\n        else if(strncmp(fname, \"https://\", 8) == 0) URL->type = BWG_HTTPS;\n        else if(strncmp(fname, \"ftp://\", 6) == 0) URL->type = BWG_FTP;\n        else URL->type = BWG_FILE;\n#else\n        URL->type = BWG_FILE;\n#endif\n\n        //local file?\n        if(URL->type == BWG_FILE) {\n            URL->filePos = -1; //This signals that nothing has been read\n            URL->x.fp = fopen(fname, \"rb\");\n            if(!(URL->x.fp)) {\n                free(URL);\n                fprintf(stderr, \"[urlOpen] Couldn't open %s for reading\\n\", fname);\n                return NULL;\n            }\n#ifndef NOCURL\n        } else {\n            //Remote file, set up the memory buffer and get CURL ready\n            URL->memBuf = malloc(GLOBAL_DEFAULTBUFFERSIZE);\n            if(!(URL->memBuf)) {\n                free(URL);\n                fprintf(stderr, \"[urlOpen] Couldn't allocate enough space for the file buffer!\\n\");\n                return NULL;\n            }\n            URL->bufSize = GLOBAL_DEFAULTBUFFERSIZE;\n            URL->x.curl = curl_easy_init();\n            if(!(URL->x.curl)) {\n                fprintf(stderr, \"[urlOpen] curl_easy_init() failed!\\n\");\n                goto error;\n            }\n            //Negotiate a reasonable HTTP authentication method\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Failed instructing curl to use any HTTP authentication it finds to be suitable!\\n\");\n                goto error;\n            }\n            //Follow redirects\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Failed instructing curl to follow redirects!\\n\");\n                goto error;\n            }\n            //Set the URL\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_URL, fname) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Couldn't set CURLOPT_URL!\\n\");\n                goto error;\n            }\n            //Set the range, which doesn't do anything for HTTP\n            sprintf(range, \"0-%lu\", URL->bufSize-1);\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_RANGE, range) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Couldn't set CURLOPT_RANGE (%s)!\\n\", range);\n                goto error;\n            }\n            //Set the callback info, which means we no longer need to directly deal with sockets and header!\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_WRITEFUNCTION, bwFillBuffer) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Couldn't set CURLOPT_WRITEFUNCTION!\\n\");\n                goto error;\n            }\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_WRITEDATA, (void*)URL) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Couldn't set CURLOPT_WRITEDATA!\\n\");\n                goto error;\n            }\n            //Ignore certificate errors with https, libcurl just isn't reliable enough with conda\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_SSL_VERIFYPEER, 0) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Couldn't set CURLOPT_SSL_VERIFYPEER to 0!\\n\");\n                goto error;\n            }\n            if(curl_easy_setopt(URL->x.curl, CURLOPT_SSL_VERIFYHOST, 0) != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] Couldn't set CURLOPT_SSL_VERIFYHOST to 0!\\n\");\n                goto error;\n            }\n            if(callBack) {\n                code = callBack(URL->x.curl);\n                if(code != CURLE_OK) {\n                    fprintf(stderr, \"[urlOpen] The user-supplied call back function returned an error: %s\\n\", curl_easy_strerror(code));\n                    goto error;\n                }\n            }\n            code = curl_easy_perform(URL->x.curl);\n            errno = 0; //Sometimes curl_easy_perform leaves a random errno remnant\n            if(code != CURLE_OK) {\n                fprintf(stderr, \"[urlOpen] curl_easy_perform received an error: %s\\n\", curl_easy_strerror(code));\n                goto error;\n            }\n#endif\n        }\n    } else {\n        URL->type = BWG_FILE;\n        URL->x.fp = fopen(fname, mode);\n        if(!(URL->x.fp)) {\n            free(URL);\n            fprintf(stderr, \"[urlOpen] Couldn't open %s for writing\\n\", fname);\n            return NULL;\n        }\n    }\n    if(url) free(url);\n    if(req) free(req);\n    return URL;\n\n#ifndef NOCURL\nerror:\n    if(url) free(url);\n    if(req) free(req);\n    free(URL->memBuf);\n    curl_easy_cleanup(URL->x.curl);\n    free(URL);\n    return NULL;\n#endif\n}\n\n//Performs the necessary free() operations and handles cleaning up curl\nvoid urlClose(URL_t *URL) {\n    if(URL->type == BWG_FILE) {\n        fclose(URL->x.fp);\n#ifndef NOCURL\n    } else {\n        free(URL->memBuf);\n        curl_easy_cleanup(URL->x.curl);\n#endif\n    }\n    free(URL);\n}\n"
  },
  {
    "path": "pyBigWig.c",
    "content": "#include <Python.h>\n#include <inttypes.h>\n#include \"pyBigWig.h\"\n\n#ifdef WITHNUMPY\n#include <float.h>\n#include \"numpy/npy_common.h\"\n#include \"numpy/halffloat.h\"\n#include \"numpy/ndarrayobject.h\"\n#include \"numpy/arrayscalars.h\"\n\nint lsize = NPY_SIZEOF_LONG;\n\n//Raises an exception on error, which should be checked\nuint32_t getNumpyU32(PyArrayObject *obj, Py_ssize_t i) {\n    int dtype;\n    char *p;\n    uint32_t o = 0;\n    npy_intp stride;\n\n    //Get the dtype\n    dtype = PyArray_TYPE(obj);\n    //Get the stride\n    stride = PyArray_STRIDE(obj, 0);\n    p = PyArray_BYTES(obj) + i*stride;\n\n    switch(dtype) {\n    case NPY_INT8:\n        if(((int8_t *) p)[0] < 0) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received an integer < 0!\\n\");\n            goto error;\n        }\n        o += ((int8_t *) p)[0];\n        break;\n    case NPY_INT16:\n        if(((int16_t *) p)[0] < 0) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received an integer < 0!\\n\");\n            goto error;\n        }\n        o += ((int16_t *) p)[0];\n        break;\n    case NPY_INT32:\n        if(((int32_t *) p)[0] < 0) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received an integer < 0!\\n\");\n            goto error;\n        }\n        o += ((int32_t *) p)[0];\n        break;\n    case NPY_INT64:\n        if(((int64_t *) p)[0] < 0) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received an integer < 0!\\n\");\n            goto error;\n        }\n        o += ((int64_t *) p)[0];\n        break;\n    case NPY_UINT8:\n        o += ((uint8_t *) p)[0];\n        break;\n    case NPY_UINT16:\n        o += ((uint16_t *) p)[0];\n        break;\n    case NPY_UINT32:\n        o += ((uint32_t *) p)[0];\n        break;\n    case NPY_UINT64:\n        if(((uint64_t *) p)[0] > (uint32_t) -1) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received an integer larger than possible for a 32bit unsigned integer!\\n\");\n            goto error;\n        }\n        o += ((uint64_t *) p)[0];\n        break;\n    default:\n        PyErr_SetString(PyExc_RuntimeError, \"Received unknown data type for conversion to uint32_t!\\n\");\n        goto error;\n        break;\n    }\n    return o;\n\nerror:\n    return 0;\n};\n\nlong getNumpyL(PyObject *obj) {\n    short s;\n    int i;\n    long l;\n    long long ll;\n    unsigned short us;\n    unsigned int ui;\n    unsigned long ul;\n    unsigned long long ull;\n    \n    if(!PyArray_IsIntegerScalar(obj)) {\n        PyErr_SetString(PyExc_RuntimeError, \"Received non-Integer scalar type for conversion to long!\\n\");\n        return 0;\n    }\n\n    if(PyArray_IsScalar(obj, Short)) {\n        s = ((PyShortScalarObject *)obj)->obval;\n        l = s;\n    } else if(PyArray_IsScalar(obj, Int)) {\n        i = ((PyLongScalarObject *)obj)->obval;\n        l = i;\n    } else if(PyArray_IsScalar(obj, Long)) {\n        l = ((PyLongScalarObject *)obj)->obval;\n    } else if(PyArray_IsScalar(obj, LongLong)) {\n        ll = ((PyLongScalarObject *)obj)->obval;\n        l = ll;\n    } else if(PyArray_IsScalar(obj, UShort)) {\n        us = ((PyLongScalarObject *)obj)->obval;\n        l = us;\n    } else if(PyArray_IsScalar(obj, UInt)) {\n        ui = ((PyLongScalarObject *)obj)->obval;\n        l = ui;\n    } else if(PyArray_IsScalar(obj, ULong)) {\n        ul = ((PyLongScalarObject *)obj)->obval;\n        l = ul;\n    } else if(PyArray_IsScalar(obj, ULongLong)) {\n        ull = ((PyLongScalarObject *)obj)->obval;\n        l = ull;\n    } else {\n        PyErr_SetString(PyExc_RuntimeError, \"Received unknown scalar type for conversion to long!\\n\");\n        return 0;\n    }\n\n    return l;\n}\n\n//Raises an exception on error, which should be checked\nfloat getNumpyF(PyArrayObject *obj, Py_ssize_t i) {\n    int dtype;\n    char *p;\n    float o = 0.0;\n    npy_intp stride;\n\n    //Get the dtype\n    dtype = PyArray_TYPE(obj);\n    //Get the stride\n    stride = PyArray_STRIDE(obj, 0);\n    p = PyArray_BYTES(obj) + i*stride;\n\n    switch(dtype) {\n    case NPY_FLOAT16:\n        return npy_half_to_float(((npy_half*)p)[0]);\n    case NPY_FLOAT32:\n        return ((float*)p)[0];\n    case NPY_FLOAT64:\n        if(((double*)p)[0] > FLT_MAX) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received a floating point value greater than possible for a 32-bit float!\\n\");\n            goto error;\n        }\n        if(((double*)p)[0] < -FLT_MAX) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received a floating point value less than possible for a 32-bit float!\\n\");\n            goto error;\n        }\n        o += ((double*)p)[0];\n        return o;\n    default:\n        PyErr_SetString(PyExc_RuntimeError, \"Received unknown data type for conversion to float!\\n\");\n        goto error;\n        break;\n    }\n    return o;\n\nerror:\n    return 0;\n}\n\n//The calling function needs to free the result\nchar *getNumpyStr(PyArrayObject *obj, Py_ssize_t i) {\n    char *p , *o = NULL;\n    npy_intp stride, j;\n    int dtype;\n\n    //Get the dtype\n    dtype = PyArray_TYPE(obj);\n    //Get the stride\n    stride = PyArray_STRIDE(obj, 0);\n    p = PyArray_BYTES(obj) + i*stride;\n\n    switch(dtype) {\n    case NPY_STRING:\n        o = calloc(1, stride + 1);\n        strncpy(o, p, stride);\n        return o;\n    case NPY_UNICODE:\n        o = calloc(1, stride/4 + 1);\n        for(j=0; j<stride/4; j++) o[j] = (char) ((uint32_t*)p)[j];\n        return o;\n    default:\n        PyErr_SetString(PyExc_RuntimeError, \"Received unknown data type!\\n\");\n        break;\n    }\n    return NULL;\n}\n#endif\n\n//Return 1 if there are any entries at all\nint hasEntries(bigWigFile_t *bw) {\n    if(bw->hdr->indexOffset != 0) return 1;  // No index, no entries pyBigWig issue #111\n    //if(bw->hdr->nBasesCovered > 0) return 1;  // Sometimes headers are broken\n    return 0;\n}\n\nPyObject* pyBwEnter(pyBigWigFile_t*self, PyObject *args) {\n    bigWigFile_t *bw = self->bw;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not opened!\");\n        return NULL;\n    }\n\n    Py_INCREF(self);\n\n    return (PyObject*) self;\n}\n\nPyObject* pyBwOpen(PyObject *self, PyObject *pyFname) {\n    char *fname = NULL;\n    char *mode = \"r\";\n    pyBigWigFile_t *pybw;\n    bigWigFile_t *bw = NULL;\n\n    if(!PyArg_ParseTuple(pyFname, \"s|s\", &fname, &mode)) goto error;\n\n    //Open the local/remote file\n    if(strchr(mode, 'w') != NULL || bwIsBigWig(fname, NULL)) {\n        bw = bwOpen(fname, NULL, mode);\n    } else {\n        bw = bbOpen(fname, NULL);\n    }\n    if(!bw) {\n        fprintf(stderr, \"[pyBwOpen] bw is NULL!\\n\");\n        goto error;\n    }\n    if(!mode || !strchr(mode, 'w')) {\n        if(!bw->cl) goto error;\n    }\n\n    pybw = PyObject_New(pyBigWigFile_t, &bigWigFile);\n    if(!pybw) {\n        fprintf(stderr, \"[pyBwOpen] PyObject_New() returned NULL (out of memory?)!\\n\");\n        goto error;\n    }\n    pybw->bw = bw;\n    pybw->lastTid = -1;\n    pybw->lastType = -1;\n    pybw->lastSpan = (uint32_t) -1;\n    pybw->lastStep = (uint32_t) -1;\n    pybw->lastStart = (uint32_t) -1;\n    return (PyObject*) pybw;\n\nerror:\n    if(bw) bwClose(bw);\n    PyErr_SetString(PyExc_RuntimeError, \"Received an error during file opening!\");\n    return NULL;\n}\n\nstatic void pyBwDealloc(pyBigWigFile_t *self) {\n    if(self->bw) bwClose(self->bw);\n    PyObject_DEL(self);\n}\n\nstatic PyObject *pyBwClose(pyBigWigFile_t *self, PyObject *args) {\n    bwClose(self->bw);\n    self->bw = NULL;\n    Py_INCREF(Py_None);\n    return Py_None;\n}\n\n//Accessor for the header (version, nLevels, nBasesCovered, minVal, maxVal, sumData, sumSquared\nstatic PyObject *pyBwGetHeader(pyBigWigFile_t *self, PyObject *args) {\n    bigWigFile_t *bw = self->bw;\n    PyObject *ret, *val;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not opened!\");\n        return NULL;\n    }\n    if(bw->isWrite == 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"The header cannot be accessed in files opened for writing!\");\n        return NULL;\n    }\n\n    ret = PyDict_New();\n    val = PyLong_FromUnsignedLong(bw->hdr->version);\n    if(PyDict_SetItemString(ret, \"version\", val) == -1) goto error;\n    Py_DECREF(val);\n    val = PyLong_FromUnsignedLong(bw->hdr->nLevels);\n    if(PyDict_SetItemString(ret, \"nLevels\", val) == -1) goto error;\n    Py_DECREF(val);\n    val = PyLong_FromUnsignedLongLong(bw->hdr->nBasesCovered);\n    if(PyDict_SetItemString(ret, \"nBasesCovered\", val) == -1) goto error;\n    Py_DECREF(val);\n    val = PyLong_FromDouble(bw->hdr->minVal);\n    if(PyDict_SetItemString(ret, \"minVal\", val) == -1) goto error;\n    Py_DECREF(val);\n    val = PyLong_FromDouble(bw->hdr->maxVal);\n    if(PyDict_SetItemString(ret, \"maxVal\", val) == -1) goto error;\n    Py_DECREF(val);\n    val = PyLong_FromDouble(bw->hdr->sumData);\n    if(PyDict_SetItemString(ret, \"sumData\", val) == -1) goto error;\n    Py_DECREF(val);\n    val = PyLong_FromDouble(bw->hdr->sumSquared);\n    if(PyDict_SetItemString(ret, \"sumSquared\", val) == -1) goto error;\n    Py_DECREF(val);\n\n    return ret;\n\nerror :\n    Py_XDECREF(val);\n    Py_XDECREF(ret);\n    PyErr_SetString(PyExc_RuntimeError, \"Received an error while getting the bigWig header!\");\n    return NULL;\n}\n\n//Accessor for the chroms, args is optional\nstatic PyObject *pyBwGetChroms(pyBigWigFile_t *self, PyObject *args) {\n    PyObject *ret = NULL, *val;\n    bigWigFile_t *bw = self->bw;\n    char *chrom = NULL;\n    uint32_t i;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not opened!\");\n        return NULL;\n    }\n\n    if(bw->isWrite == 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"Chromosomes cannot be accessed in files opened for writing!\");\n        return NULL;\n    }\n\n    if(!(PyArg_ParseTuple(args, \"|s\", &chrom)) || !chrom) {\n        ret = PyDict_New();\n        for(i=0; i<bw->cl->nKeys; i++) {\n            val = PyLong_FromUnsignedLong(bw->cl->len[i]);\n            if(PyDict_SetItemString(ret, bw->cl->chrom[i], val) == -1) goto error;\n            Py_DECREF(val);\n        }\n    } else {\n        for(i=0; i<bw->cl->nKeys; i++) {\n            if(strcmp(bw->cl->chrom[i],chrom) == 0) {\n                ret = PyLong_FromUnsignedLong(bw->cl->len[i]);\n                break;\n            }\n        }\n    }\n\n    if(!ret) {\n        Py_INCREF(Py_None);\n        ret = Py_None;\n    }\n\n    return ret;\n\nerror :\n    Py_XDECREF(val);\n    Py_XDECREF(ret);\n    PyErr_SetString(PyExc_RuntimeError, \"Received an error while adding an item to the output dictionary!\");\n    return NULL;\n}\n\nenum bwStatsType char2enum(char *s) {\n    if(strcmp(s, \"mean\") == 0) return mean;\n    if(strcmp(s, \"std\") == 0) return stdev;\n    if(strcmp(s, \"dev\") == 0) return dev;\n    if(strcmp(s, \"max\") == 0) return max;\n    if(strcmp(s, \"min\") == 0) return min;\n    if(strcmp(s, \"cov\") == 0) return cov;\n    if(strcmp(s, \"coverage\") == 0) return cov;\n    if(strcmp(s, \"sum\") == 0) return sum;\n    return -1;\n};\n\n//Fetch summary statistics, default is the mean of the entire chromosome.\nstatic PyObject *pyBwGetStats(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {\n    bigWigFile_t *bw = self->bw;\n    double *val;\n    uint32_t start, end = -1, tid;\n    unsigned long startl = 0, endl = -1;\n    static char *kwd_list[] = {\"chrom\", \"start\", \"end\", \"type\", \"nBins\", \"exact\", \"numpy\", NULL};\n    char *chrom, *type = \"mean\";\n    PyObject *ret, *exact = Py_False, *starto = NULL, *endo = NULL;\n    PyObject *outputNumpy = Py_False;\n    int i, nBins = 1;\n    errno = 0; //In the off-chance that something elsewhere got an error and didn't clear it...\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not open!\");\n        return NULL;\n    }\n\n    if(bw->isWrite == 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"Statistics cannot be accessed in files opened for writing!\");\n        return NULL;\n    }\n\n    if(bw->type == 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"bigBed files have no statistics!\");\n        return NULL;\n    }\n\n    if(!PyArg_ParseTupleAndKeywords(args, kwds, \"s|OOsiOO\", kwd_list, &chrom, &starto, &endo, &type, &nBins, &exact, &outputNumpy)) {\n        PyErr_SetString(PyExc_RuntimeError, \"You must supply at least a chromosome!\");\n        return NULL;\n    }\n\n    //Check inputs, reset to defaults if nothing was input\n    if(!nBins) nBins = 1; //For some reason, not specifying this overrides the default!\n    if(!type) type = \"mean\";\n    tid = bwGetTid(bw, chrom);\n\n    if(starto) {\n#ifdef WITHNUMPY\n        if(PyArray_IsScalar(starto, Integer)) {\n            startl = (long) getNumpyL(starto);\n        } else \n#endif\n        if(PyLong_Check(starto)) {\n            startl = PyLong_AsLong(starto);\n#if PY_MAJOR_VERSION < 3\n        } else if(PyInt_Check(starto)) {\n            startl = PyInt_AsLong(starto);\n#endif\n        } else {\n            PyErr_SetString(PyExc_RuntimeError, \"The start coordinate must be a number!\");\n            return NULL;\n        }\n    }\n\n    if(endo) {\n#ifdef WITHNUMPY\n        if(PyArray_IsScalar(endo, Integer)) {\n            endl = (long) getNumpyL(endo);\n        } else \n#endif\n        if(PyLong_Check(endo)) {\n            endl = PyLong_AsLong(endo);\n#if PY_MAJOR_VERSION < 3\n        } else if(PyInt_Check(endo)) {\n            endl = PyInt_AsLong(endo);\n#endif\n        } else {\n            PyErr_SetString(PyExc_RuntimeError, \"The end coordinate must be a number!\");\n            return NULL;\n        }\n    }\n\n    if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];\n    if(tid == (uint32_t) -1 || startl > end || endl > end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n    start = (uint32_t) startl;\n    end = (uint32_t) endl;\n    if(end <= start || end > bw->cl->len[tid] || start >= end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n\n    if(char2enum(type) == doesNotExist) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid type!\");\n        return NULL;\n    }\n\n    //Return a list of None if there are no entries at all\n    if(!hasEntries(bw)) {\n#ifdef WITHNUMPY\n        if(outputNumpy == Py_True) {\n            val = malloc(sizeof(double)*nBins);\n            for(i=0; i<nBins; i++) {\n                val[i] = NPY_NAN;\n            }\n            npy_intp len = nBins;\n            ret = PyArray_SimpleNewFromData(1, &len, NPY_FLOAT64, (void *) val);\n            //This will break if numpy ever stops using malloc!\n            PyArray_ENABLEFLAGS((PyArrayObject*) ret, NPY_ARRAY_OWNDATA);\n        } else {\n#endif\n            ret = PyList_New(nBins);\n            for(i=0; i<nBins; i++) {\n                Py_INCREF(Py_None);\n                PyList_SetItem(ret, i, Py_None);\n            }\n#ifdef WITHNUMPY\n        }\n#endif\n        return ret;\n    }\n\n    //Get the actual statistics\n    if(exact == Py_True) {\n        val = bwStatsFromFull(bw, chrom, start, end, nBins, char2enum(type));\n    } else {\n        val = bwStats(bw, chrom, start, end, nBins, char2enum(type));\n    }\n\n    if(!val) {\n        PyErr_SetString(PyExc_RuntimeError, \"An error was encountered while fetching statistics.\");\n        return NULL;\n    }\n\n#ifdef WITHNUMPY\n    if(outputNumpy == Py_True) {\n        npy_intp len = nBins;\n        ret = PyArray_SimpleNewFromData(1, &len, NPY_FLOAT64, (void *) val);\n        //This will break if numpy ever stops using malloc!\n        PyArray_ENABLEFLAGS((PyArrayObject*) ret, NPY_ARRAY_OWNDATA);\n    } else {\n#endif\n        ret = PyList_New(nBins);\n        for(i=0; i<nBins; i++) {\n            if(isnan(val[i])) {\n                Py_INCREF(Py_None);\n                PyList_SetItem(ret, i, Py_None);\n            } else {\n                PyList_SetItem(ret, i, PyFloat_FromDouble(val[i]));\n            }\n        }\n        free(val);\n#ifdef WITHNUMPY\n    }\n#endif\n    return ret;\n}\n\n//Fetch a list of individual values\n//For bases with no coverage, the value should be None\n#ifdef WITHNUMPY\nstatic PyObject *pyBwGetValues(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {\n#else\nstatic PyObject *pyBwGetValues(pyBigWigFile_t *self, PyObject *args) {\n#endif\n    bigWigFile_t *bw = self->bw;\n    int i;\n    uint32_t start, end = -1, tid;\n    unsigned long startl, endl;\n    char *chrom;\n    PyObject *ret, *starto = NULL, *endo = NULL;\n    bwOverlappingIntervals_t *o;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not open!\");\n        return NULL;\n    }\n\n    if(bw->type == 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"bigBed files have no values! Use 'entries' instead.\");\n        return NULL;\n    }\n\n#ifdef WITHNUMPY\n    static char *kwd_list[] = {\"chrom\", \"start\", \"end\", \"numpy\", NULL};\n    PyObject *outputNumpy = Py_False;\n\n    if(!PyArg_ParseTupleAndKeywords(args, kwds, \"sOO|O\", kwd_list, &chrom, &starto, &endo, &outputNumpy)) {\n#else\n    if(!PyArg_ParseTuple(args, \"sOO\", &chrom, &starto, &endo)) {\n#endif\n        PyErr_SetString(PyExc_RuntimeError, \"You must supply a chromosome, start and end position.\\n\");\n        return NULL;\n    }\n\n    tid = bwGetTid(bw, chrom);\n\n#ifdef WITHNUMPY\n    if(PyArray_IsScalar(starto, Integer)) {\n        startl = (long) getNumpyL(starto);\n    } else\n#endif\n    if(PyLong_Check(starto)) {\n        startl = PyLong_AsLong(starto);\n#if PY_MAJOR_VERSION < 3\n    } else if(PyInt_Check(starto)) {\n        startl = PyInt_AsLong(starto);\n#endif\n    } else {\n        PyErr_SetString(PyExc_RuntimeError, \"The start coordinate must be a number!\");\n        return NULL;\n    }\n\n#ifdef WITHNUMPY\n    if(PyArray_IsScalar(endo, Integer)) {\n        endl = (long) getNumpyL(endo);\n    } else\n#endif\n    if(PyLong_Check(endo)) {\n        endl = PyLong_AsLong(endo);\n#if PY_MAJOR_VERSION < 3\n    } else if(PyInt_Check(endo)) {\n        endl = PyInt_AsLong(endo);\n#endif\n    } else {\n        PyErr_SetString(PyExc_RuntimeError, \"The end coordinate must be a number!\");\n        return NULL;\n    }\n\n    if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];\n    if(tid == (uint32_t) -1 || startl > end || endl > end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n\n    start = (uint32_t) startl;\n    end = (uint32_t) endl;\n    if(end <= start || end > bw->cl->len[tid] || start >= end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n\n    if(!hasEntries(self->bw)) {\n#ifdef WITHNUMPY\n        if(outputNumpy == Py_True) {\n            const npy_intp arr[1] = {0};\n            return PyArray_SimpleNew(1, arr, NPY_FLOAT);\n        } else {\n#endif\n            return PyList_New(0);\n#ifdef WITHNUMPY\n        }\n#endif\n    }\n\n    o = bwGetValues(self->bw, chrom, start, end, 1);\n    if(!o) {\n        PyErr_SetString(PyExc_RuntimeError, \"An error occurred while fetching values!\");\n        return NULL;\n    }\n\n#ifdef WITHNUMPY\n    if(outputNumpy == Py_True) {\n        npy_intp len = end - start;\n        ret = PyArray_SimpleNewFromData(1, &len, NPY_FLOAT, (void *) o->value);\n        //This will break if numpy ever stops using malloc!\n        PyArray_ENABLEFLAGS((PyArrayObject*) ret, NPY_ARRAY_OWNDATA);\n        free(o->start);\n        free(o->end);\n        free(o);\n    } else {\n#endif\n        ret = PyList_New(end-start);\n        for(i=0; i<(int) o->l; i++) PyList_SetItem(ret, i, PyFloat_FromDouble(o->value[i]));\n        bwDestroyOverlappingIntervals(o);\n#ifdef WITHNUMPY\n    }\n#endif\n\n    return ret;\n}\n\nstatic PyObject *pyBwGetIntervals(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {\n    bigWigFile_t *bw = self->bw;\n    uint32_t start, end = -1, tid, i;\n    unsigned long startl = 0, endl = -1;\n    static char *kwd_list[] = {\"chrom\", \"start\", \"end\", NULL};\n    bwOverlappingIntervals_t *intervals = NULL;\n    char *chrom;\n    PyObject *ret, *starto = NULL, *endo = NULL;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not opened!\");\n        return NULL;\n    }\n\n    if(bw->isWrite == 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"Intervals cannot be accessed in files opened for writing!\");\n        return NULL;\n    }\n\n    if(bw->type == 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"bigBed files have no intervals! Use 'entries()' instead.\");\n        return NULL;\n    }\n\n    if(!PyArg_ParseTupleAndKeywords(args, kwds, \"s|OO\", kwd_list, &chrom, &starto, &endo)) {\n        PyErr_SetString(PyExc_RuntimeError, \"You must supply at least a chromosome.\\n\");\n        return NULL;\n    }\n\n    //Sanity check\n    tid = bwGetTid(bw, chrom);\n    if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];\n    if(tid == (uint32_t) -1 || startl > end || endl > end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n\n    if(starto) {\n#ifdef WITHNUMPY\n        if(PyArray_IsScalar(starto, Integer)) {\n            startl = (long) getNumpyL(starto);\n        } else\n#endif\n        if(PyLong_Check(starto)) {\n            startl = PyLong_AsLong(starto);\n#if PY_MAJOR_VERSION < 3\n        } else if(PyInt_Check(starto)) {\n            startl = PyInt_AsLong(starto);\n#endif\n        } else {\n            PyErr_SetString(PyExc_RuntimeError, \"The start coordinate must be a number!\");\n            return NULL;\n        }\n    }\n\n    if(endo) {\n#ifdef WITHNUMPY\n        if(PyArray_IsScalar(endo, Integer)) {\n            endl = (long) getNumpyL(endo);\n        } else\n#endif\n        if(PyLong_Check(endo)) {\n            endl = PyLong_AsLong(endo);\n#if PY_MAJOR_VERSION < 3\n        } else if(PyInt_Check(endo)) {\n            endl = PyInt_AsLong(endo);\n#endif\n        } else {\n            PyErr_SetString(PyExc_RuntimeError, \"The end coordinate must be a number!\");\n            return NULL;\n        }\n    }\n\n    start = (uint32_t) startl;\n    end = (uint32_t) endl;\n    if(end <= start || end > bw->cl->len[tid] || start >= end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n\n    //Check for empty files\n    if(!hasEntries(bw)) {\n        Py_INCREF(Py_None);\n        return Py_None;\n    }\n\n    //Get the intervals\n    intervals = bwGetOverlappingIntervals(bw, chrom, start, end);\n    if(!intervals) {\n        PyErr_SetString(PyExc_RuntimeError, \"An error occurred while fetching the overlapping intervals!\");\n        return NULL;\n    }\n    if(!intervals->l) {\n        Py_INCREF(Py_None);\n        return Py_None;\n    }\n\n    ret = PyTuple_New(intervals->l);\n    for(i=0; i<intervals->l; i++) {\n        if(PyTuple_SetItem(ret, i, Py_BuildValue(\"(iif)\", intervals->start[i], intervals->end[i], intervals->value[i]))) {\n            Py_DECREF(ret);\n            bwDestroyOverlappingIntervals(intervals);\n            PyErr_SetString(PyExc_RuntimeError, \"An error occurred while constructing the output tuple!\");\n            return NULL;\n        }\n    }\n\n    bwDestroyOverlappingIntervals(intervals);\n    return ret;\n}\n\n#if PY_MAJOR_VERSION >= 3\n//Return 1 iff obj is a ready unicode type\nint PyString_Check(PyObject *obj) {\n    if(PyUnicode_Check(obj)) {\n        return PyUnicode_READY(obj)+1;\n    }\n    return 0;\n}\n\n//I don't know what happens if PyBytes_AsString(NULL) is used...\nchar *PyString_AsString(PyObject *obj) {\n    return PyUnicode_AsUTF8(obj);\n}\n#endif\n\n//Will return 1 for long or int types currently\nint isNumeric(PyObject *obj) {\n#ifdef WITHNUMPY\n    if(PyArray_IsScalar(obj, Integer)) return 1;\n#endif\n#if PY_MAJOR_VERSION < 3\n    if(PyInt_Check(obj)) return 1;\n#endif\n    return PyLong_Check(obj);\n}\n\n//On error, throws a runtime error, so use PyErr_Occurred() after this\nuint32_t Numeric2Uint(PyObject *obj) {\n    long l;\n#if PY_MAJOR_VERSION < 3\n    if(PyInt_Check(obj)) {\n        return (uint32_t) PyInt_AsLong(obj);\n    }\n#endif\n    l = PyLong_AsLong(obj);\n    //Check bounds\n    if(l > 0xFFFFFFFF) {\n        PyErr_SetString(PyExc_RuntimeError, \"Length out of bounds for a bigWig file!\");\n        return (uint32_t) -1;\n    }\n    return (uint32_t) l;\n}\n\n//This runs bwCreateHdr, bwCreateChromList, and bwWriteHdr\nPyObject *pyBwAddHeader(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {\n    bigWigFile_t *bw = self->bw;\n    char **chroms = NULL;\n    int64_t n;\n    uint32_t *lengths = NULL, len;\n    int32_t maxZooms = 10;\n    long zoomTmp = 10;\n    static char *kwd_list[] = {\"cl\", \"maxZooms\", NULL};\n    PyObject *InputTuple = NULL, *tmpObject, *tmpObject2;\n    Py_ssize_t i, pyLen;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not open!\");\n        return NULL;\n    }\n\n    if(!PyArg_ParseTupleAndKeywords(args, kwds, \"O|k\", kwd_list, &InputTuple, &zoomTmp)) {\n        PyErr_SetString(PyExc_RuntimeError, \"Illegal arguments\");\n        return NULL;\n    }\n    maxZooms = zoomTmp;\n\n    //Ensure that we received a list\n    if(!PyList_Check(InputTuple)) {\n        PyErr_SetString(PyExc_RuntimeError, \"You MUST input a list of tuples (e.g., [('chr1', 1000), ('chr2', 2000)]!\");\n        goto error;\n    }\n    pyLen = PyList_Size(InputTuple);\n    if(pyLen < 1) {\n        PyErr_SetString(PyExc_RuntimeError, \"You input an empty list!\");\n        goto error;\n    }\n    n = pyLen;\n\n    lengths = calloc(n, sizeof(uint32_t));\n    chroms = calloc(n, sizeof(char*));\n    if(!lengths || !chroms) {\n        PyErr_SetString(PyExc_RuntimeError, \"Couldn't allocate lengths or chroms!\");\n        goto error;\n    }\n\n    //Convert the tuple into something more useful in C\n    for(i=0; i<pyLen; i++) {\n        tmpObject = PyList_GetItem(InputTuple, i);\n        if(!tmpObject) {\n            PyErr_SetString(PyExc_RuntimeError, \"Couldn't get a tuple!\");\n            goto error;\n        }\n        if(!PyTuple_Check(tmpObject)) {\n            PyErr_SetString(PyExc_RuntimeError, \"The input list is not made up of tuples!\");\n            goto error;\n        }\n        if(PyTuple_Size(tmpObject) != 2) {\n            PyErr_SetString(PyExc_RuntimeError, \"One tuple does not contain exactly 2 members!\");\n            goto error;\n        }\n\n        //Chromosome\n        tmpObject2 = PyTuple_GetItem(tmpObject, 0); //This returns NULL in python3?!?\n        if(!PyString_Check(tmpObject2)) {\n            PyErr_SetString(PyExc_RuntimeError, \"The first element of each tuple MUST be a string!\");\n            goto error;\n        }\n        chroms[i] = PyString_AsString(tmpObject2);\n        if(!chroms[i]) {\n            PyErr_SetString(PyExc_RuntimeError, \"Received something other than a string for a chromosome name!\");\n            goto error;\n        }\n\n        //Length\n        tmpObject2 = PyTuple_GetItem(tmpObject, 1);\n        if(!isNumeric(tmpObject2)) {\n            PyErr_SetString(PyExc_RuntimeError, \"The second element of each tuple MUST be an integer!\");\n            goto error;\n        }\n        len = Numeric2Uint(tmpObject2);\n        if(PyErr_Occurred()) goto error;\n        if(zoomTmp > 0xFFFFFFFF) {\n            PyErr_SetString(PyExc_RuntimeError, \"A requested length is longer than what can be stored in a bigWig file!\");\n            goto error;\n        }\n        lengths[i] = len;\n    }\n\n    //Create the header\n    if(bwCreateHdr(bw, maxZooms)) {\n        PyErr_SetString(PyExc_RuntimeError, \"Received an error in bwCreateHdr\");\n        goto error;\n    }\n\n    //Create the chromosome list\n    bw->cl = bwCreateChromList((const char* const*) chroms, lengths, n);\n    if(!bw->cl) {\n        PyErr_SetString(PyExc_RuntimeError, \"Received an error in bwCreateChromList\");\n        goto error;\n    }\n\n    //Write the header\n    if(bwWriteHdr(bw)) {\n        PyErr_SetString(PyExc_RuntimeError, \"Received an error while writing the bigWig header\");\n        goto error;\n    }\n\n    if(lengths) free(lengths);\n    if(chroms) free(chroms);\n\n    Py_INCREF(Py_None);\n    return Py_None;\n\nerror:\n    if(lengths) free(lengths);\n    if(chroms) free(chroms);\n    return NULL;\n}\n\n//1 on true, 0 on false\nint isType0(PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *values) {\n    int rv = 0;\n    Py_ssize_t i, sz = 0;\n    PyObject *tmp;\n\n    if(!PyList_Check(chroms)\n#ifdef WITHNUMPY\n        && !PyArray_Check(chroms)\n#endif\n        ) return rv;\n    if(!PyList_Check(starts)\n#ifdef WITHNUMPY\n        && !PyArray_Check(starts)\n#endif\n        ) return rv;\n    if(!PyList_Check(ends)\n#ifdef WITHNUMPY\n        && !PyArray_Check(ends)\n#endif\n        ) return rv;\n    if(!PyList_Check(values)\n#ifdef WITHNUMPY\n        && !PyArray_Check(values)\n#endif\n        ) return rv;\n    if(PyList_Check(chroms)) sz = PyList_Size(chroms);\n#ifdef WITHNUMPY\n    if(PyArray_Check(chroms)) sz += PyArray_Size(chroms);\n#endif\n\n    if(PyList_Check(starts)) {\n        if(sz != PyList_Size(starts)) return rv;\n#ifdef WITHNUMPY\n    } else {\n        if(sz != PyArray_Size(starts)) return rv;\n#endif\n    }\n    if(PyList_Check(ends)) {\n        if(sz != PyList_Size(ends)) return rv;\n#ifdef WITHNUMPY\n    } else {\n        if(sz != PyArray_Size(ends)) return rv;\n#endif\n    }\n    if(PyList_Check(values)) {\n        if(sz != PyList_Size(values)) return rv;\n#ifdef WITHNUMPY\n    } else {\n        if(sz != PyArray_Size(values)) return rv;\n#endif\n    }\n\n    //Ensure chroms contains strings, etc.\n    if(PyList_Check(chroms)) {\n        for(i=0; i<sz; i++) {\n            tmp = PyList_GetItem(chroms, i);\n            if(!PyString_Check(tmp)) return rv;\n        }\n#ifdef WITHNUMPY\n    } else {\n        if(!PyArray_ISSTRING( (PyArrayObject*) chroms)) return rv;\n#endif\n    }\n    if(PyList_Check(starts)) {\n        for(i=0; i<sz; i++) {\n            tmp = PyList_GetItem(starts, i);\n            if(!isNumeric(tmp)) return rv;\n        }\n#ifdef WITHNUMPY\n    } else {\n        if(!PyArray_ISINTEGER( (PyArrayObject*) starts)) return rv;\n#endif\n    }\n    if(PyList_Check(ends)) {\n        for(i=0; i<sz; i++) {\n            tmp = PyList_GetItem(ends, i);\n            if(!isNumeric(tmp)) return rv;\n        }\n#ifdef WITHNUMPY\n    } else {\n        if(!PyArray_ISINTEGER( (PyArrayObject*) ends)) return rv;\n#endif\n    }\n    if(PyList_Check(values)) {\n        for(i=0; i<sz; i++) {\n            tmp = PyList_GetItem(values, i);\n            if(!PyFloat_Check(tmp)) return rv;\n        }\n#ifdef WITHNUMPY\n    } else {\n        if(!PyArray_ISFLOAT((PyArrayObject*) values)) return rv;\n#endif\n    }\n    return 1;\n}\n\n//single chrom, multiple starts, single span\nint isType1(PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span) {\n    int rv = 0;\n    Py_ssize_t i, sz = 0;\n    PyObject *tmp;\n\n    if(!PyString_Check(chroms)) return rv;\n    if(!PyList_Check(starts)\n#ifdef WITHNUMPY\n        && !PyArray_Check(starts)\n#endif\n        ) return rv;\n    if(!PyList_Check(values)\n#ifdef WITHNUMPY\n        && !PyArray_Check(values)\n#endif\n        ) return rv;\n    if(!isNumeric(span)) return rv;\n\n    if(PyList_Check(starts)) sz = PyList_Size(starts);\n#ifdef WITHNUMPY\n    if(PyArray_Check(starts)) sz += PyArray_Size(starts);\n#endif\n\n    if(PyList_Check(values)) if(sz != PyList_Size(values)) return rv;\n#ifdef WITHNUMPY\n    if(PyArray_Check(values)) if(sz != PyArray_Size(values)) return rv;\n#endif\n\n    if(PyList_Check(starts)) {\n        for(i=0; i<sz; i++) {\n            tmp = PyList_GetItem(starts, i);\n            if(!isNumeric(tmp)) return rv;\n        }\n#ifdef WITHNUMPY\n    } else {\n        if(!PyArray_ISINTEGER( (PyArrayObject*) starts)) return rv;\n#endif\n    }\n    if(PyList_Check(values)) {\n        for(i=0; i<sz; i++) {\n            tmp = PyList_GetItem(values, i);\n            if(!PyFloat_Check(tmp)) return rv;\n        }\n#ifdef WITHNUMPY\n    } else {\n        if(!PyArray_ISFLOAT( (PyArrayObject*) values)) return rv;\n#endif\n    }\n    return 1;\n}\n\n//Single chrom, single start, single span, single step, multiple values\nint isType2(PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span, PyObject *step) {\n    int rv = 0;\n    Py_ssize_t i, sz;\n    PyObject *tmp;\n\n    if(!isNumeric(span)) return rv;\n    if(!isNumeric(step)) return rv;\n    if(!PyString_Check(chroms)) return rv;\n    if(!isNumeric(starts)) return rv;\n\n    if(PyList_Check(values)) {\n        sz = PyList_Size(values);\n        for(i=0; i<sz; i++) {\n            tmp = PyList_GetItem(values, i);\n            if(!PyFloat_Check(tmp)) return rv;\n        }\n#ifdef WITHNUMPY\n    } else {\n        if(!PyArray_ISFLOAT( (PyArrayObject*) values)) return rv;\n#endif\n    }\n    rv = 1;\n    return rv;\n}\n\nint getType(PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *values, PyObject *span, PyObject *step) {\n    if(!chroms) return -1;\n    if(!starts) return -1;\n    if(!values) return -1;\n    if(chroms && starts && ends && values && isType0(chroms, starts, ends, values)) return 0;\n    if(chroms && starts && span && values && isType1(chroms, starts, values, span)) return 1;\n    if(chroms && starts && values && span && step && isType2(chroms, starts, values, span, step)) return 2;\n    return -1;\n}\n\n//1: Can use a bwAppend* function. 0: must use a bwAdd* function\nint canAppend(pyBigWigFile_t *self, int desiredType, PyObject *chroms, PyObject *starts, PyObject *span, PyObject *step) {\n    bigWigFile_t *bw = self->bw;\n    Py_ssize_t i, sz = 0;\n    uint32_t tid, uspan, ustep, ustart;\n    PyObject *tmp;\n#ifdef WITHNUMPY\n    char *chrom;\n#endif\n\n    if(self->lastType == -1) return 0;\n    if(self->lastTid == -1) return 0;\n    if(self->lastType != desiredType) return 0;\n\n    //We can only append if (A) we have the same type or (B) the same chromosome (and compatible span/step/starts\n    if(desiredType == 0) {\n        //We need (A) chrom == lastTid and (B) all chroms to be the same\n        if(PyList_Check(chroms)) sz = PyList_Size(chroms);\n#ifdef WITHNUMPY\n        if(PyArray_Check(chroms)) sz = PyArray_Size(chroms);\n#endif\n\n        for(i=0; i<sz; i++) {\n#ifdef WITHNUMPY\n            if(PyArray_Check(chroms)) {\n                chrom = getNumpyStr((PyArrayObject*)chroms, i);\n                tid = bwGetTid(bw, chrom);\n                free(chrom);\n            } else {\n#endif\n                tmp = PyList_GetItem(chroms, i);\n                tid = bwGetTid(bw, PyString_AsString(tmp));\n#ifdef WITHNUMPY\n            }\n#endif\n            if(tid != (uint32_t) self->lastTid) return 0;\n        }\n\n#ifdef WITHNUMPY\n        if(PyArray_Check(starts)) {\n            ustart = getNumpyU32((PyArrayObject*)starts, 0);\n        } else {\n#endif\n            ustart = Numeric2Uint(PyList_GetItem(starts, 0));\n#ifdef WITHNUMPY\n        }\n#endif\n        if(PyErr_Occurred()) return 0;\n        if(ustart < self->lastStart) return 0;\n        return 1;\n    } else if(desiredType == 1) {\n        //We need (A) chrom == lastTid, (B) all chroms to be the same, and (C) equal spans\n        uspan = Numeric2Uint(span);\n        if(PyErr_Occurred()) return 0;\n        if(uspan != self->lastSpan) return 0;\n        if(!PyString_Check(chroms)) return 0;\n        tid = bwGetTid(bw, PyString_AsString(chroms));\n        if(tid != (uint32_t) self->lastTid) return 0;\n\n#ifdef WITHNUMPY\n        if(PyList_Check(starts)) ustart = Numeric2Uint(PyList_GetItem(starts, 0));\n        else ustart = getNumpyU32((PyArrayObject*) starts, 0);\n#else\n        ustart = Numeric2Uint(PyList_GetItem(starts, 0));\n#endif\n        if(PyErr_Occurred()) return 0;\n        if(ustart < self->lastStart) return 0;\n        return 1;\n    } else if(desiredType == 2) {\n        //We need (A) chrom == lastTid, (B) span/step to be equal and (C) compatible starts\n        tid = bwGetTid(bw, PyString_AsString(chroms));\n        if(tid != (uint32_t) self->lastTid) return 0;\n        uspan = Numeric2Uint(span);\n        if(PyErr_Occurred()) return 0;\n        if(uspan != self->lastSpan) return 0;\n        ustep = Numeric2Uint(step);\n        if(PyErr_Occurred()) return 0;\n        if(ustep != self->lastStep) return 0;\n\n        //But is the start position compatible?\n        ustart = Numeric2Uint(starts);\n        if(PyErr_Occurred()) return 0;\n        if(ustart != self->lastStart) return 0;\n        return 1;\n    }\n\n    return 0;\n}\n\n//Returns 0 on success, 1 on error. Sets self->lastTid && self->lastStart (unless there was an error)\nint PyAddIntervals(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *values) {\n    bigWigFile_t *bw = self->bw;\n    Py_ssize_t i, sz = 0;\n    char **cchroms = NULL;\n    uint32_t n, *ustarts = NULL, *uends = NULL;\n    float *fvalues = NULL;\n    int rv;\n\n    if(PyList_Check(starts)) sz = PyList_Size(starts);\n#ifdef WITHNUMPY\n    if(PyArray_Check(starts)) sz += PyArray_Size(starts);\n#endif\n    n = (uint32_t) sz;\n\n    //Allocate space\n    cchroms = calloc(n, sizeof(char*));\n    ustarts = calloc(n, sizeof(uint32_t));\n    uends = calloc(n, sizeof(uint32_t));\n    fvalues = calloc(n, sizeof(float));\n    if(!cchroms || !ustarts || !uends || !fvalues) goto error;\n\n    for(i=0; i<sz; i++) {\n        if(PyList_Check(chroms)) {\n            cchroms[i] = PyString_AsString(PyList_GetItem(chroms, i));\n#ifdef WITHNUMPY\n        } else {\n            cchroms[i] = getNumpyStr((PyArrayObject*)chroms, i);\n#endif\n        }\n        if(PyList_Check(starts)) {\n            ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));\n#ifdef WITHNUMPY\n        } else {\n            ustarts[i] = getNumpyU32((PyArrayObject*)starts, i);\n#endif\n        }\n        if(PyErr_Occurred()) goto error;\n        if(PyList_Check(ends)) {\n            uends[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(ends, i));\n#ifdef WITHNUMPY\n        } else {\n            uends[i] = getNumpyU32((PyArrayObject*)ends, i);\n#endif\n        }\n        if(PyErr_Occurred()) goto error;\n        if(PyList_Check(values)) {\n            fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));\n#ifdef WITHNUMPY\n        } else {\n            fvalues[i] = getNumpyF((PyArrayObject*)values, i);\n#endif\n        }\n        if(PyErr_Occurred()) goto error;\n    }\n\n    rv = bwAddIntervals(bw, (const char * const*) cchroms, ustarts, uends, fvalues, n);\n    if(!rv) {\n        self->lastTid = bwGetTid(bw, cchroms[n-1]);\n        self->lastStart = uends[n-1];\n    }\n    if(!PyList_Check(chroms)) {\n        for(i=0; i<n; i++) free(cchroms[i]);\n    }\n    free(cchroms);\n    free(ustarts);\n    free(uends);\n    free(fvalues);\n    return rv;\n\nerror:\n    if(cchroms) free(cchroms);\n    if(ustarts) free(ustarts);\n    if(uends) free(uends);\n    if(fvalues) free(fvalues);\n    return 1;\n}\n\n//Returns 0 on success, 1 on error. Update self->lastStart\nint PyAppendIntervals(pyBigWigFile_t *self, PyObject *starts, PyObject *ends, PyObject *values) {\n    bigWigFile_t *bw = self->bw;\n    Py_ssize_t i, sz = 0;\n    uint32_t n, *ustarts = NULL, *uends = NULL;\n    float *fvalues = NULL;\n    int rv;\n\n    if(PyList_Check(starts)) sz = PyList_Size(starts);\n#ifdef WITHNUMPY\n    if(PyArray_Check(starts)) sz += PyArray_Size(starts);\n#endif\n    n = (uint32_t) sz;\n\n    //Allocate space\n    ustarts = calloc(n, sizeof(uint32_t));\n    uends = calloc(n, sizeof(uint32_t));\n    fvalues = calloc(n, sizeof(float));\n    if(!ustarts || !uends || !fvalues) goto error;\n\n    for(i=0; i<sz; i++) {\n        if(PyList_Check(starts)) {\n            ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));\n#ifdef WITHNUMPY\n        } else {\n            ustarts[i] = getNumpyU32((PyArrayObject*) starts, i);\n#endif\n        }\n        if(PyErr_Occurred()) goto error;\n        if(PyList_Check(ends)) {\n            uends[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(ends, i));\n#ifdef WITHNUMPY\n        } else {\n            uends[i] = getNumpyU32((PyArrayObject*) ends, i);\n#endif\n        }\n        if(PyErr_Occurred()) goto error;\n        if(PyList_Check(values)) {\n            fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));\n#ifdef WITHNUMPY\n        } else {\n            fvalues[i] = getNumpyF((PyArrayObject*) values, i);\n#endif\n        }\n        if(PyErr_Occurred()) goto error;\n    }\n    rv = bwAppendIntervals(bw, ustarts, uends, fvalues, n);\n    if(rv) self->lastStart = uends[n-1];\n    free(ustarts);\n    free(uends);\n    free(fvalues);\n    return rv;\n\nerror:\n    if(ustarts) free(ustarts);\n    if(uends) free(uends);\n    if(fvalues) free(fvalues);\n    return 1;\n}\n\n//Returns 0 on success, 1 on error. Sets self->lastTid/lastStart/lastSpan (unless there was an error)\nint PyAddIntervalSpans(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span) {\n    bigWigFile_t *bw = self->bw;\n    Py_ssize_t i, sz = 0;\n    char *cchroms = NULL;\n    uint32_t n, *ustarts = NULL, uspan;\n    float *fvalues = NULL;\n    int rv;\n\n    if(PyList_Check(starts)) sz = PyList_Size(starts);\n#ifdef WITHNUMPY\n    else if(PyArray_Check(starts)) sz += PyArray_Size(starts);\n#endif\n    n = (uint32_t) sz;\n\n    //Allocate space\n    ustarts = calloc(n, sizeof(uint32_t));\n    fvalues = calloc(n, sizeof(float));\n    if(!ustarts || !fvalues) goto error;\n    uspan = (uint32_t) PyLong_AsLong(span);\n    cchroms = PyString_AsString(chroms);\n\n    if(PyList_Check(starts)) {\n        for(i=0; i<sz; i++) {\n            ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));\n            if(PyErr_Occurred()) goto error;\n        }\n#ifdef WITHNUMPY\n    } else {\n        for(i=0; i<sz; i++) {\n            ustarts[i] = getNumpyU32((PyArrayObject*) starts, i);\n            if(PyErr_Occurred()) goto error;\n        }\n#endif\n    }\n    if(PyList_Check(values)) {\n        for(i=0; i<sz; i++) {\n            fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));\n            if(PyErr_Occurred()) goto error;\n        }\n#ifdef WITHNUMPY\n    } else {\n        for(i=0; i<sz; i++) {\n            fvalues[i] = getNumpyF((PyArrayObject*) values, i);\n            if(PyErr_Occurred()) goto error;\n        }\n#endif\n    }\n\n    rv = bwAddIntervalSpans(bw, cchroms, ustarts, uspan, fvalues, n);\n    if(!rv) {\n        self->lastTid = bwGetTid(bw, cchroms);\n        self->lastSpan = uspan;\n        self->lastStart = ustarts[n-1]+uspan;\n    }\n    free(ustarts);\n    free(fvalues);\n    return rv;\n\nerror:\n    if(ustarts) free(ustarts);\n    if(fvalues) free(fvalues);\n    return 1;\n}\n\n//Returns 0 on success, 1 on error. Updates self->lastStart\nint PyAppendIntervalSpans(pyBigWigFile_t *self, PyObject *starts, PyObject *values) {\n    bigWigFile_t *bw = self->bw;\n    Py_ssize_t i, sz = 0;\n    uint32_t n, *ustarts = NULL;\n    float *fvalues = NULL;\n    int rv;\n\n    if(PyList_Check(starts)) sz = PyList_Size(starts);\n#ifdef WITHNUMPY\n    else if(PyArray_Check(starts)) sz += PyArray_Size(starts);\n#endif\n    n = (uint32_t) sz;\n\n    //Allocate space\n    ustarts = calloc(n, sizeof(uint32_t));\n    fvalues = calloc(n, sizeof(float));\n    if(!ustarts || !fvalues) goto error;\n\n    if(PyList_Check(starts)) {\n        for(i=0; i<sz; i++) {\n            ustarts[i] = (uint32_t) PyLong_AsLong(PyList_GetItem(starts, i));\n            if(PyErr_Occurred()) goto error;\n        }\n#ifdef WITHNUMPY\n    } else {\n        for(i=0; i<sz; i++) {\n            ustarts[i] = getNumpyU32((PyArrayObject*) starts, i);\n            if(PyErr_Occurred()) goto error;\n        }\n#endif\n    }\n    if(PyList_Check(values)) {\n        for(i=0; i<sz; i++) {\n            fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));\n            if(PyErr_Occurred()) goto error;\n        }\n#ifdef WITHNUMPY\n    } else {\n        for(i=0; i<sz; i++) {\n            fvalues[i] = getNumpyF((PyArrayObject*) values, i);\n            if(PyErr_Occurred()) goto error;\n        }\n#endif\n    }\n\n    rv = bwAppendIntervalSpans(bw, ustarts, fvalues, n);\n    if(rv) self->lastStart = ustarts[n-1] + self->lastSpan;\n    free(ustarts);\n    free(fvalues);\n    return rv;\n\nerror:\n    if(ustarts) free(ustarts);\n    if(fvalues) free(fvalues);\n    return 1;\n}\n\n//Returns 0 on success, 1 on error. Sets self->lastTid/self->lastSpan/lastStep/lastStart (unless there was an error)\nint PyAddIntervalSpanSteps(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *values, PyObject *span, PyObject *step) {\n    bigWigFile_t *bw = self->bw;\n    Py_ssize_t i, sz = 0;\n    char *cchrom = NULL;\n    uint32_t n, ustarts, uspan, ustep;\n    float *fvalues = NULL;\n    int rv;\n\n    if(PyList_Check(values)) sz = PyList_Size(values);\n#ifdef WITHNUMPY\n    else if(PyArray_Check(values)) sz += PyArray_Size(values);\n#endif\n    n = (uint32_t) sz;\n\n    //Allocate space\n    fvalues = calloc(n, sizeof(float));\n    if(!fvalues) goto error;\n    uspan = (uint32_t) PyLong_AsLong(span);\n    ustep = (uint32_t) PyLong_AsLong(step);\n    ustarts = (uint32_t) PyLong_AsLong(starts);\n    cchrom = PyString_AsString(chroms);\n\n    if(PyList_Check(values)) {\n        for(i=0; i<sz; i++) fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));\n#ifdef WITHNUMPY\n    } else {\n        for(i=0; i<sz; i++) {\n            fvalues[i] = getNumpyF((PyArrayObject*) values, i);\n            if(PyErr_Occurred()) goto error;\n        }\n#endif\n    }\n\n    rv = bwAddIntervalSpanSteps(bw, cchrom, ustarts, uspan, ustep, fvalues, n);\n    if(!rv) {\n        self->lastTid = bwGetTid(bw, cchrom);\n        self->lastSpan = uspan;\n        self->lastStep = ustep;\n        self->lastStart = ustarts + ustep*n;\n    }\n    free(fvalues);\n    return rv;\n\nerror:\n    if(fvalues) free(fvalues);\n    return 1;\n}\n\n//Returns 0 on success, 1 on error. Sets self->lastStart\nint PyAppendIntervalSpanSteps(pyBigWigFile_t *self, PyObject *values) {\n    bigWigFile_t *bw = self->bw;\n    Py_ssize_t i, sz = 0;\n    uint32_t n;\n    float *fvalues = NULL;\n    int rv;\n\n    if(PyList_Check(values)) sz = PyList_Size(values);\n#ifdef WITHNUMPY\n    else if(PyArray_Check(values)) sz += PyArray_Size(values);\n#endif\n    n = (uint32_t) sz;\n\n    //Allocate space\n    fvalues = calloc(n, sizeof(float));\n    if(!fvalues) goto error;\n\n    if(PyList_Check(values)) {\n        for(i=0; i<sz; i++) fvalues[i] = (float) PyFloat_AsDouble(PyList_GetItem(values, i));\n#ifdef WITHNUMPY\n    } else {\n        for(i=0; i<sz; i++) {\n            fvalues[i] = getNumpyF((PyArrayObject*) values, i);\n            if(PyErr_Occurred()) goto error;\n        }\n#endif\n    }\n\n    rv = bwAppendIntervalSpanSteps(bw, fvalues, n);\n    if(!rv) self->lastStart += self->lastStep * n;\n    free(fvalues);\n    return rv;\n\nerror:\n    if(fvalues) free(fvalues);\n    return 1;\n}\n\n//Checks and ensures that (A) the entries are sorted correctly and don't overlap and (B) that the come after things that have already been added.\n//Returns 1 on correct input, 0 on incorrect input\nint addEntriesInputOK(pyBigWigFile_t *self, PyObject *chroms, PyObject *starts, PyObject *ends, PyObject *span, PyObject *step, int type) {\n    uint32_t lastTid = self->lastTid;\n    uint32_t lastEnd = self->lastStart;\n    uint32_t cTid, ustart, uend, uspan, ustep;\n    Py_ssize_t i, sz = 0;\n    PyObject *tmp;\n#ifdef WITHNUMPY\n    char *tmpStr;\n#endif\n\n    if(type == 0) {\n        //Each chrom:start-end needs to be properly formed and come after prior entries\n        if(PyList_Check(starts)) sz = PyList_Size(starts);\n#ifdef WITHNUMPY\n        if(PyArray_Check(starts)) sz += PyArray_Size(starts);\n#endif\n        if(sz == 0) return 0;\n        for(i=0; i<sz; i++) {\n#ifdef WITHNUMPY\n            if(PyArray_Check(chroms)) {\n                tmpStr = getNumpyStr((PyArrayObject*)chroms, i);\n                cTid = bwGetTid(self->bw, tmpStr);\n                free(tmpStr);\n            } else {\n#endif\n                tmp = PyList_GetItem(chroms, i);\n                cTid = bwGetTid(self->bw, PyString_AsString(tmp));\n#ifdef WITHNUMPY\n            }\n#endif\n            if(PyErr_Occurred()) return 0;\n            if(cTid == (uint32_t) -1) return 0;\n\n#ifdef WITHNUMPY\n            if(PyArray_Check(starts)) {\n                ustart = getNumpyU32((PyArrayObject*)starts, i);\n            } else {\n#endif\n                ustart = Numeric2Uint(PyList_GetItem(starts, i));\n#ifdef WITHNUMPY\n            }\n#endif\n            if(PyErr_Occurred()) return 0;\n#ifdef WITHNUMPY\n            if(PyArray_Check(ends)) {\n                uend = getNumpyU32((PyArrayObject*) ends, i);\n            } else {\n#endif\n                uend = Numeric2Uint(PyList_GetItem(ends, i));\n#ifdef WITHNUMPY\n            }\n#endif\n            if(PyErr_Occurred()) return 0;\n\n            if(ustart >= uend) return 0;\n            if(lastTid != (uint32_t) -1) {\n                if(lastTid > cTid) return 0;\n                if(lastTid == cTid) {\n                    if(ustart < lastEnd) return 0;\n                }\n            }\n            lastTid = cTid;\n            lastEnd = uend;\n        }\n        return 1;\n    } else if(type == 1) {\n        //each chrom:start-(start+span) needs to be properly formed and come after prior entries\n        if(!PyList_Check(starts)\n#ifdef WITHNUMPY\n            && !PyArray_Check(starts)\n#endif\n        ) return 0;\n        if(PyList_Check(starts)) sz = PyList_Size(starts);\n#ifdef WITHNUMPY\n        else if(PyArray_Check(starts)) sz += PyArray_Size(starts);\n#endif\n        uspan = Numeric2Uint(span);\n        if(PyErr_Occurred()) return 0;\n        if(uspan < 1) return 0;\n        if(sz == 0) return 0;\n        cTid = bwGetTid(self->bw, PyString_AsString(chroms));\n        if(cTid == (uint32_t) -1) return 0;\n        if(lastTid != (uint32_t) -1) {\n            if(lastTid > cTid) return 0;\n        }\n        for(i=0; i<sz; i++) {\n#ifdef WITHNUMPY\n            if(PyArray_Check(starts)) {\n                ustart = getNumpyU32((PyArrayObject*)starts, i);\n            } else {\n#endif\n                ustart = Numeric2Uint(PyList_GetItem(starts, i));\n#ifdef WITHNUMPY\n            }\n#endif\n            if(PyErr_Occurred()) return 0;\n            uend = ustart + uspan;\n\n            if(lastTid == cTid) {\n                if(ustart < lastEnd) return 0;\n            }\n            lastTid = cTid;\n            lastEnd = uend;\n        }\n        return 1;\n    } else if(type == 2) {\n        //The chrom and start need to be appropriate\n        cTid = bwGetTid(self->bw, PyString_AsString(chroms));\n        if(cTid == (uint32_t) -1) return 0;\n        ustart = Numeric2Uint(starts);\n        if(PyErr_Occurred()) return 0;\n        uspan = Numeric2Uint(span);\n        if(PyErr_Occurred()) return 0;\n        if(uspan < 1) return 0;\n        ustep = Numeric2Uint(step);\n        if(PyErr_Occurred()) return 0;\n        if(ustep < 1) return 0;\n        if(lastTid != (uint32_t) -1) {\n            if(lastTid > cTid) return 0;\n            if(lastTid == cTid) {\n                if(ustart < lastEnd) return 0;\n            }\n        }\n        return 1;\n    }\n    return 0;\n}\n\nPyObject *pyBwAddEntries(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {\n    static char *kwd_list[] = {\"chroms\", \"starts\", \"ends\", \"values\", \"span\", \"step\", \"validate\", NULL};\n    PyObject *chroms = NULL, *starts = NULL, *ends = NULL, *values = NULL, *span = NULL, *step = NULL;\n    PyObject *validate = Py_True;\n    int desiredType;\n\n    if(!self->bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigWig file handle is not open!\");\n        return NULL;\n    }\n\n    if(!PyArg_ParseTupleAndKeywords(args, kwds, \"OO|OOOOO\", kwd_list, &chroms, &starts, &ends, &values, &span, &step, &validate)) {\n        PyErr_SetString(PyExc_RuntimeError, \"Illegal arguments\");\n        return NULL;\n    }\n\n    desiredType = getType(chroms, starts, ends, values, span, step);\n    if(desiredType == -1) {\n        PyErr_SetString(PyExc_RuntimeError, \"You must provide a valid set of entries. These can be comprised of any of the following: \\n\"\n\"1. A list of each of chromosomes, start positions, end positions and values.\\n\"\n\"2. A list of each of start positions and values. Also, a chromosome and span must be specified.\\n\"\n\"3. A list values, in which case a single chromosome, start position, span and step must be specified.\\n\");\n        return NULL;\n    }\n\n    if(validate == Py_True  && !addEntriesInputOK(self, chroms, starts, ends, span, step, desiredType)) {\n        PyErr_SetString(PyExc_RuntimeError, \"The entries you tried to add are out of order, precede already added entries, or otherwise use illegal values.\\n\"\n\" Please correct this and try again.\\n\");\n        return NULL;\n    }\n\n    if(canAppend(self, desiredType, chroms, starts, span, step)) {\n        switch(desiredType) {\n            case 0:\n                if(PyAppendIntervals(self, starts, ends, values)) goto error;\n                break;\n            case 1:\n                if(PyAppendIntervalSpans(self, starts, values)) goto error;\n                break;\n            case 2:\n                if(PyAppendIntervalSpanSteps(self, values)) goto error;\n                break;\n        }\n    } else {\n        switch(desiredType) {\n            case 0:\n                if(PyAddIntervals(self, chroms, starts, ends, values)) goto error;\n                break;\n            case 1:\n                if(PyAddIntervalSpans(self, chroms, starts, values, span)) goto error;\n                break;\n            case 2:\n                if(PyAddIntervalSpanSteps(self, chroms, starts, values, span, step)) goto error;\n                break;\n        }\n    }\n    self->lastType = desiredType;\n\n    Py_INCREF(Py_None);\n    return Py_None;\n\nerror:\n    return NULL;\n}\n\n/**************************************************************\n*\n* BigBed functions, added in 0.3.0\n*\n**************************************************************/\n\nstatic PyObject *pyBBGetEntries(pyBigWigFile_t *self, PyObject *args, PyObject *kwds) {\n    bigWigFile_t *bw = self->bw;\n    uint32_t i;\n    uint32_t start, end = -1, tid;\n    unsigned long startl, endl;\n    char *chrom;\n    static char *kwd_list[] = {\"chrom\", \"start\", \"end\", \"withString\", NULL};\n    PyObject *ret, *t, *starto = NULL, *endo = NULL;\n    PyObject *withStringPy = Py_True;\n    int withString = 1;\n    bbOverlappingEntries_t *o;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigBed file handle is not open!\");\n        return NULL;\n    }\n\n    if(bw->type == 0) {\n        PyErr_SetString(PyExc_RuntimeError, \"bigWig files have no entries! Use 'intervals' or 'values' instead.\");\n        return NULL;  \n    }\n\n    if(!PyArg_ParseTupleAndKeywords(args, kwds, \"sOO|O\", kwd_list, &chrom, &starto, &endo, &withStringPy)) {\n        PyErr_SetString(PyExc_RuntimeError, \"You must supply a chromosome, start and end position.\\n\");\n        return NULL;\n    }\n\n    tid = bwGetTid(bw, chrom);\n\n#ifdef WITHNUMPY\n    if(PyArray_IsScalar(starto, Integer)) {\n        startl = (long) getNumpyL(starto);\n    } else\n#endif\n    if(PyLong_Check(starto)) {\n        startl = PyLong_AsLong(starto);\n#if PY_MAJOR_VERSION < 3\n    } else if(PyInt_Check(starto)) {\n        startl = PyInt_AsLong(starto);\n#endif\n    } else {\n        PyErr_SetString(PyExc_RuntimeError, \"The start coordinate must be a number!\");\n        return NULL;\n    }\n\n#ifdef WITHNUMPY\n    if(PyArray_IsScalar(endo, Integer)) {\n        endl = (long) getNumpyL(endo);\n    } else\n#endif\n    if(PyLong_Check(endo)) {\n        endl = PyLong_AsLong(endo);\n#if PY_MAJOR_VERSION < 3\n    } else if(PyInt_Check(endo)) {\n        endl = PyInt_AsLong(endo);\n#endif\n    } else {\n        PyErr_SetString(PyExc_RuntimeError, \"The end coordinate must be a number!\");\n        return NULL;\n    }\n\n    if(endl == (unsigned long) -1 && tid != (uint32_t) -1) endl = bw->cl->len[tid];\n    if(tid == (uint32_t) -1 || startl > end || endl > end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n    start = (uint32_t) startl;\n    end = (uint32_t) endl;\n    if(end <= start || end > bw->cl->len[tid] || start >= end) {\n        PyErr_SetString(PyExc_RuntimeError, \"Invalid interval bounds!\");\n        return NULL;\n    }\n\n    if(withStringPy == Py_False) withString = 0;\n\n    o = bbGetOverlappingEntries(bw, chrom, start, end, withString);\n    if(!o) {\n        PyErr_SetString(PyExc_RuntimeError, \"An error occurred while fetching the overlapping entries!\\n\");\n        return NULL;\n    }\n    if(!o->l) {\n        Py_INCREF(Py_None);\n        return Py_None;\n    }\n\n    ret = PyList_New(o->l);\n    if(!ret) goto error;\n\n    for(i=0; i<o->l; i++) {\n        if(withString) {\n            t = Py_BuildValue(\"(iis)\", o->start[i], o->end[i], o->str[i]);\n        } else {\n            t = Py_BuildValue(\"(ii)\", o->start[i], o->end[i]);\n        }\n        if(!t) goto error;\n        PyList_SetItem(ret, i, t);\n    }\n\n    bbDestroyOverlappingEntries(o);\n    return ret;\n\nerror:\n    Py_DECREF(ret);\n    bbDestroyOverlappingEntries(o);\n    PyErr_SetString(PyExc_RuntimeError, \"An error occurred while constructing the output list and tuple!\");\n    return NULL;\n}\n\nstatic PyObject *pyBBGetSQL(pyBigWigFile_t *self, PyObject *args) {\n    bigWigFile_t *bw = self->bw;\n    char *str = bbGetSQL(bw);\n    size_t len = 0;\n    PyObject *o = NULL;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigBed file handle is not open!\");\n        return NULL;\n    }\n\n    if(!str) {\n        Py_INCREF(Py_None);\n        return Py_None;\n    }\n    len = strlen(str);\n\n#if PY_MAJOR_VERSION >= 3\n    o = PyBytes_FromStringAndSize(str, len);\n#else\n    o = PyString_FromStringAndSize(str, len);\n#endif\n    if(str) free(str);\n\n    return o;\n}\n\nstatic PyObject *pyIsBigWig(pyBigWigFile_t *self, PyObject *args) {\n    bigWigFile_t *bw = self->bw;\n    if(bw->type == 0) {\n        Py_INCREF(Py_True);\n        return Py_True;\n    }\n\n    Py_INCREF(Py_False);\n    return Py_False;\n}\n\nstatic PyObject *pyIsBigBed(pyBigWigFile_t *self, PyObject *args) {\n    bigWigFile_t *bw = self->bw;\n\n    if(!bw) {\n        PyErr_SetString(PyExc_RuntimeError, \"The bigBed file handle is not open!\");\n        return NULL;\n    }\n\n    if(bw->type == 1) {\n        Py_INCREF(Py_True);\n        return Py_True;\n    }\n\n    Py_INCREF(Py_False);\n    return Py_False;\n}\n\n/**************************************************************\n*\n* End of bigBed functions\n*\n**************************************************************/\n\n#if PY_MAJOR_VERSION >= 3\nPyMODINIT_FUNC PyInit_pyBigWig(void) {\n#else\nPyMODINIT_FUNC initpyBigWig(void) {\n#endif\n    PyObject *res;\n    errno = 0; //just in case\n\n#if PY_MAJOR_VERSION >= 3\n    if(Py_AtExit(bwCleanup)) return NULL;\n    if(PyType_Ready(&bigWigFile) < 0) return NULL;\n    if(bwInit(128000)) return NULL;\n    res = PyModule_Create(&pyBigWigmodule);\n    if(!res) return NULL;\n#else\n    if(Py_AtExit(bwCleanup)) return;\n    if(PyType_Ready(&bigWigFile) < 0) return;\n    if(bwInit(128000)) return;\n    res = Py_InitModule3(\"pyBigWig\", bwMethods, \"A module for handling bigWig files\");\n#endif\n\n    Py_INCREF(&bigWigFile);\n    PyModule_AddObject(res, \"pyBigWig\", (PyObject *) &bigWigFile);\n\n#ifdef WITHNUMPY\n    //Add the numpy constant\n    import_array(); //Needed for numpy stuff to work\n    PyModule_AddIntConstant(res, \"numpy\", 1);\n#else\n    PyModule_AddIntConstant(res, \"numpy\", 0);\n#endif\n#ifdef NOCURL\n    PyModule_AddIntConstant(res, \"remote\", 0);\n#else\n    PyModule_AddIntConstant(res, \"remote\", 1);\n#endif\n    PyModule_AddStringConstant(res, \"__version__\", pyBigWigVersion);\n\n#if PY_MAJOR_VERSION >= 3\n    return res;\n#endif\n}\n"
  },
  {
    "path": "pyBigWig.h",
    "content": "#include <Python.h>\n#include <structmember.h>\n#include \"bigWig.h\"\n\n#define pyBigWigVersion \"0.3.25\"\n\ntypedef struct {\n    PyObject_HEAD\n    bigWigFile_t *bw;\n    int32_t lastTid; //The TID of the last written entry (or -1)\n    uint32_t lastSpan; //The span of the last written entry (if applicable)\n    uint32_t lastStep; //The step of the last written entry (if applicable)\n    uint32_t lastStart; //The next start position (if applicable)\n    int lastType; //The type of the last written entry\n} pyBigWigFile_t;\n\nstatic PyObject *pyBwOpen(PyObject *self, PyObject *pyFname);\nstatic PyObject *pyBwEnter(pyBigWigFile_t *self, PyObject *args);\nstatic PyObject *pyBwClose(pyBigWigFile_t *pybw, PyObject *args);\nstatic PyObject *pyBwGetChroms(pyBigWigFile_t *pybw, PyObject *args);\nstatic PyObject *pyIsBigWig(pyBigWigFile_t *pybw, PyObject *args);\nstatic PyObject *pyIsBigBed(pyBigWigFile_t *pybw, PyObject *args);\nstatic PyObject *pyBwGetStats(pyBigWigFile_t *pybw, PyObject *args, PyObject *kwds);\n#ifdef WITHNUMPY\nstatic PyObject *pyBwGetValues(pyBigWigFile_t *pybw, PyObject *args, PyObject *kwds);\n#else\nstatic PyObject *pyBwGetValues(pyBigWigFile_t *pybw, PyObject *args);\n#endif\nstatic PyObject *pyBwGetIntervals(pyBigWigFile_t *pybw, PyObject *args, PyObject *kwds);\n\tstatic PyObject *pyBBGetEntries(pyBigWigFile_t *pybw, PyObject *args, PyObject *kwds);\nstatic PyObject *pyBBGetSQL(pyBigWigFile_t *pybw, PyObject *args);\nstatic PyObject *pyBwGetHeader(pyBigWigFile_t *pybw, PyObject *args);\nstatic PyObject *pyBwAddHeader(pyBigWigFile_t *pybw, PyObject *args, PyObject *kwds);\nstatic PyObject *pyBwAddEntries(pyBigWigFile_t *pybw, PyObject *args, PyObject *kwds);\nstatic void pyBwDealloc(pyBigWigFile_t *pybw);\n\n//The function types aren't actually correct...\nstatic PyMethodDef bwMethods[] = {\n    {\"open\", (PyCFunction)pyBwOpen, METH_VARARGS,\n\"Open a bigWig or bigBed file. For remote files, give a URL starting with HTTP,\\n\\\nFTP, or HTTPS.\\n\\\n\\n\\\nOptional arguments:\\n\\\n    mode: An optional mode. The default is 'r', which opens a file for reading.\\n\\\n          If you specify a mode containing 'w' then you'll instead open a file\\n\\\n          for writing. Note that you then need to add an appropriate header\\n\\\n          before use. For bigBed files, only reading is supported.\\n\\\n\\n\\\nReturns:\\n\\\n   A bigWigFile object on success, otherwise None.\\n\\\n\\n\\\nArguments:\\n\\\n    file: The name of a bigWig file.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"some_file.bw\\\")\\n\"},\n    {NULL, NULL, 0, NULL}\n};\n\nstatic PyMethodDef bwObjMethods[] = {\n    {\"header\", (PyCFunction)pyBwGetHeader, METH_VARARGS,\n\"Returns the header of a bigWig file. This contains information such as: \\n\\\n  * The version number of the file ('version').\\n\\\n  * The number of zoom levels ('nLevels').\\n\\\n  * The number of bases covered ('nBasesCovered').\\n\\\n  * The minimum value ('minVal').\\n\\\n  * The maximum value ('maxVal').\\n\\\n  * The sum of all values ('sumData').\\n\\\n  * The sum of the square of all values ('sumSquared').\\n\\\nThese are returned as a dictionary.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"some_file.bw\\\")\\n\\\n>>> bw.header()\\n\\\n{'maxVal': 2L, 'sumData': 272L, 'minVal': 0L, 'version': 4L,\\n\\\n'sumSquared': 500L, 'nLevels': 1L, 'nBasesCovered': 154L}\\n\\\n>>> bw.close()\\n\"},\n    {\"close\", (PyCFunction)pyBwClose, METH_VARARGS,\n\"Close a bigWig file.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"some_file.bw\\\")\\n\\\n>>> bw.close()\\n\"},\n    {\"isBigWig\", (PyCFunction)pyIsBigWig, METH_VARARGS,\n\"Returns True if the object is a bigWig file (otherwise False).\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"some_file.bigWig\\\")\\n\\\n>>> bw.isBigWig()\\n\\\nTrue\\n\\\n>>> bw.isBigBed()\\n\\\nFalse\\n\"},\n    {\"isBigBed\", (PyCFunction)pyIsBigBed, METH_VARARGS,\n\"Returns true if the object is a bigBed file (otherwise False).\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"some_file.bigBed\\\")\\n\\\n>>> bw.isBigWig()\\n\\\nFalse\\n\\\n>>> bw.isBigBed()\\n\\\nTrue\\n\"},\n    {\"chroms\", (PyCFunction)pyBwGetChroms, METH_VARARGS,\n\"Return a chromosome: length dictionary. The order is typically not\\n\\\nalphabetical and the lengths are long (thus the 'L' suffix).\\n\\\n\\n\\\nOptional arguments:\\n\\\n    chrom: An optional chromosome name\\n\\\n\\n\\\nReturns:\\n\\\n    A list of chromosome lengths or a dictionary of them.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"test/test.bw\\\")\\n\\\n>>> bw.chroms()\\n\\\n{'1': 195471971L, '10': 130694993L}\\n\\\n\\n\\\nNote that you may optionally supply a specific chromosome:\\n\\\n\\n\\\n>>> bw.chroms(\\\"chr1\\\")\\n\\\n195471971L\\n\\\n\\n\\\nIf you specify a non-existant chromosome then no output is produced:\\n\\\n\\n\\\n>>> bw.chroms(\\\"foo\\\")\\n\\\n>>>\\n\"},\n    {\"stats\", (PyCFunction)pyBwGetStats, METH_VARARGS|METH_KEYWORDS,\n\"Return summary statistics for a given range. On error, this function throws a\\n\\\nruntime exception.\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chr:   Chromosome name\\n\\\n\\n\\\nKeyword arguments:\\n\\\n    start: Starting position\\n\\\n    end:   Ending position\\n\\\n    type:  Summary type (mean, min, max, coverage, std, sum), default 'mean'.\\n\\\n    nBins: Number of bins into which the range should be divided before\\n\\\n           computing summary statistics. The default is 1.\\n\\\n    exact: By default, pyBigWig uses the same method as Kent's tools from UCSC\\n\\\n           for computing statistics. This means that 'zoom levels' may be\\n\\\n           used, rather than actual values (please see the pyBigWig repository\\n\\\n           on github for further information on this). To avoid this behaviour,\\n\\\n           simply specify 'exact=True'. Note that values returned will then\\n\\\n           differ from what UCSC, IGV, and similar other tools will report.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"test/test.bw\\\")\\n\\\n>>> bw.stats(\\\"1\\\", 0, 3)\\n\\\n[0.2000000054637591]\\n\\\n\\n\\\nThis is the mean value over the range 1:1-3 (in 1-based coordinates). If\\n\\\nthe start and end positions aren't given the entire chromosome is used.\\n\\\nThere are additional optional parameters 'type' and 'nBins'. 'type'\\n\\\nspecifies the type of summary information to calculate, which is 'mean'\\n\\\nby default. Other possibilites for 'type' are: 'min' (minimum value),\\n\\\n'max' (maximum value), 'coverage' (number of covered bases), and 'std'\\n\\\n (standard deviation). 'nBins' defines how many bins the region will be\\n\\\n divided into and defaults to 1.\\n\\\n\\n\\\n>>> bw.stats(\\\"1\\\", 0, 3, type=\\\"min\\\")\\n\\\n[0.10000000149011612]\\n\\\n>>> bw.stats(\\\"1\\\", 0, 3, type=\\\"max\\\")\\n\\\n[0.30000001192092896]\\n\\\n>>> bw.stats(\\\"1\\\", 0, 10, type=\\\"coverage\\\")\\n\\\n[0.30000000000000004]\\n\\\n>>> bw.stats(\\\"1\\\", 0, 3, type=\\\"std\\\")\\n\\\n[0.10000000521540645]\\n\\\n>>> bw.stats(\\\"1\\\",99,200, type=\\\"max\\\", nBins=2)\\n\\\n[1.399999976158142, 1.5]\\n\"},\n#ifdef WITHNUMPY\n    {\"values\", (PyCFunction)pyBwGetValues, METH_VARARGS|METH_KEYWORDS,\n\"Retrieve the value stored for each position (or None). On error, a runtime\\n\\\nexception is thrown.\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chr:   Chromosome name\\n\\\n    start: Starting position\\n\\\n    end:   Ending position\\n\\\n\\n\\\nOptional arguments:\\n\\\n    numpy: If True, return a numpy array rather than a list of values. This\\n\\\n           is generally more memory efficient. Note that this option is only\\n\\\n           available if pyBigWig was installed with numpy support (check the\\n\\\n           pyBigWig.numpy() function).\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"test/test.bw\\\")\\n\\\n>>> bw.values(\\\"1\\\", 0, 3)\\n\\\n[0.10000000149011612, 0.20000000298023224, 0.30000001192092896]\\n\\\n\\n\\\nThe length of the returned list will always match the length of the\\n\\\nrange. Any uncovered bases will have a value of None.\\n\\\n\\n\\\n>>> bw.values(\\\"1\\\", 0, 4)\\n\\\n[0.10000000149011612, 0.20000000298023224, 0.30000001192092896, None]\\n\\\n\\n\"},\n#else\n    {\"values\", (PyCFunction)pyBwGetValues, METH_VARARGS,\n\"Retrieve the value stored for each position (or None). On error, a runtime\\n\\\nexception is thrown.\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chr:   Chromosome name\\n\\\n    start: Starting position\\n\\\n    end:   Ending position\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"test/test.bw\\\")\\n\\\n>>> bw.values(\\\"1\\\", 0, 3)\\n\\\n[0.10000000149011612, 0.20000000298023224, 0.30000001192092896]\\n\\\n\\n\\\nThe length of the returned list will always match the length of the\\n\\\nrange. Any uncovered bases will have a value of None.\\n\\\n\\n\\\n>>> bw.values(\\\"1\\\", 0, 4)\\n\\\n[0.10000000149011612, 0.20000000298023224, 0.30000001192092896, None]\\n\\\n\\n\"},\n#endif\n    {\"intervals\", (PyCFunction)pyBwGetIntervals, METH_VARARGS|METH_KEYWORDS,\n\"Retrieve each interval covering a part of a chromosome/region. On error, a\\n\\\nruntime exception is thrown.\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chr:   Chromosome name\\n\\\n\\n\\\nKeyword arguments:\\n\\\n    start: Starting position\\n\\\n    end:   Ending position\\n\\\n\\n\\\nIf start and end aren't specified, the entire chromosome is returned.\\n\\\nThe returned object is a tuple containing the starting position, end\\n\\\nposition, and value of each interval in the file. As with all bigWig\\n\\\npositions, those returned are 0-based half-open (e.g., a start of 0 and\\n\\\nend of 10 specifies the first 10 positions).\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bw = pyBigWig.open(\\\"test/test.bw\\\")\\n\\\n>>> bw.intervals(\\\"1\\\", 0, 3)\\n\\\n((0, 1, 0.10000000149011612), (1, 2, 0.20000000298023224),\\n\\\n (2, 3, 0.30000001192092896))\\n\\\n>>> bw.close()\"},\n    {\"entries\", (PyCFunction) pyBBGetEntries, METH_VARARGS|METH_KEYWORDS,\n\"Retrieves entries from a bigBed file. These can optionally contain the string\\n\\\nassociated with each entry.\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chr:   Chromosome name\\n\\\n\\n\\\nKeyword arguments:\\n\\\n    start: Starting position\\n\\\n    end:   Ending position\\n\\\n    withString: If True, return the string associated with each entry.\\n\\\n           Default True.\\n\\\n\\n\\\nThe output is a list of tuples, with members \\\"start\\\", \\\"end\\\", and \\\"string\\\"\\n\\\n(assuming \\\"withString=True\\\"). If there are no overlapping entries, then None\\n\\\nis returned.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bb = pyBigWig.open(\\\"https://www.encodeproject.org/files/ENCFF001JBR/@@download/ENCFF001JBR.bigBed\\\")\\n\\\n>>> print(bw.entries('chr1',10000000,10020000))\\n\\\n[(10009333, 10009640, '61035\\t130\\t-\\t0.026\\t0.42\\t404'),\\n\\\n(10014007, 10014289, '61047\\t136\\t-\\t0.029\\t0.42\\t404'),\\n\\\n(10014373, 10024307, '61048\\t630\\t-\\t5.420\\t0.00\\t2672399')]\\n\\\n>>> print(bb.entries(\\\"chr1\\\", 10000000, 10000500, withString=False))\\n\\\n[(10009333, 10009640), (10014007, 10014289), (10014373, 10024307)]\\n\\\n\\n\"},\n    {\"SQL\", (PyCFunction) pyBBGetSQL, METH_VARARGS,\n\"Returns the SQL string associated with the file. This is typically useful for\\n\\\nbigBed files, where this determines what is held in each column of the text\\n\\\nstring associated with entries.\\n\\\n\\n\\\nIf there is no SQL string, then None is returned.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> bb = pyBigWig.open(\\\"https://www.encodeproject.org/files/ENCFF001JBR/@@download/ENCFF001JBR.bigBed\\\")\\n\\\n>>> print(bb.SQL())\\n\\\ntable RnaElements\\n\\\n\\\"BED6 + 3 scores for RNA Elements data \\\"\\n\\\n    (\\n\\\n    string chrom;      \\\"Reference sequence chromosome or scaffold\\\"\\n\\\n    uint   chromStart; \\\"Start position in chromosome\\\"\\n\\\n    uint   chromEnd;   \\\"End position in chromosome\\\"\\n\\\n    string name;       \\\"Name of item\\\"\\n\\\n    uint   score;      \\\"Normalized score from 0-1000\\\"\\n\\\n    char[1] strand;    \\\"+ or - or . for unknown\\\"\\n\\\n    float level;       \\\"Expression level such as RPKM or FPKM. Set to -1 for no data.\\\"\\n\\\n    float signif;      \\\"Statistical significance such as IDR. Set to -1 for no data.\\\"\\n\\\n    uint score2;       \\\"Additional measurement/count e.g. number of reads. Set to 0 for no data.\\\"\\n\\\n    )\\n\\\n\\n\\\n\\n\"},\n    {\"addHeader\", (PyCFunction)pyBwAddHeader, METH_VARARGS|METH_KEYWORDS,\n\"Adds a header to a file opened for writing. This MUST be called before adding\\n\\\nany entries. On error, a runtime exception is thrown.\\n\\\n\\n\\\nPositional arguments:\\n\\\n    cl:    A chromosome list, of the form (('chr1', 1000), ('chr2', 2000), ...).\\n\\\n           In other words, each element of the list is a tuple containing a\\n\\\n           chromosome name and its associated length.\\n\\\n\\n\\\nKeyword arguments:\\n\\\n    maxZooms:  The maximum number of zoom levels. The value must be >=0. The\\n\\\n               default is 10.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> import tempfile\\n\\\n>>> import os\\n\\\n>>> ofile = tempfile.NamedTemporaryFile(delete=False)\\n\\\n>>> oname = ofile.name\\n\\\n>>> ofile.close()\\n\\\n>>> bw = pyBigWig.open(oname, 'w')\\n\\\n>>> bw.addHeader([(\\\"1\\\", 1000000), (\\\"2\\\", 1500000)], maxZooms=0)\\n\\\n>>> bw.close()\\n\\\n>>> os.remove(oname)\"},\n    {\"addEntries\", (PyCFunction)pyBwAddEntries, METH_VARARGS|METH_KEYWORDS,\n\"Adds one or more entries to a bigWig file. This returns nothing, but throws a\\n\\\nruntime exception on error.\\n\\\n\\n\\\nThis function always accepts an optional 'validate' option. If set to 'True',\\n\\\nwhich is the default, the input entries are checked to ensure that they come\\n\\\nafter previously entered entries. This comes with significant overhead, so if\\n\\\nthis is instead 'False' then this validation is not performed.\\n\\\n\\n\\\nThere are three manners in which entries can be stored in bigWig files.\\n\\\n\\n\\\n\\n\\\nbedGraph-like entries (12 bytes each):\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chrom:  A list of chromosome. These MUST match those added with addHeader().\\n\\\n    starts: A list of start positions. These are 0-based.\\n\\\n\\n\\\nKeyword arguments:\\n\\\n    ends:   A list of end positions. These are 0-based half open, so a start of\\n\\\n            0 and end of 10 specifies the first 10 bases.\\n\\\n    values: A list of values.\\n\\\n\\n\\\n\\n\\\nVariable-step entries (8 bytes each):\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chrom:  A chromosome name. This MUST match one added with addHeader().\\n\\\n    starts: A list of start positions. These are 0-based.\\n\\\n\\n\\\nKeyword arguments:\\n\\\n    values: A list of values.\\n\\\n    span:   A span width. This is an integer value and specifies how many bases\\n\\\n            each entry describes. An entry with a start position of 0 and a span\\n\\\n            of 10 describes the first 10 bases.\\n\\\n\\n\\\n\\n\\\nFixed-step entries (4 bytes each):\\n\\\n\\n\\\nPositional arguments:\\n\\\n    chrom:  A chromosome name. This MUST match one added with addHeader().\\n\\\n    starts: A start position. These are 0-based. The start position of each\\n\\\n            entry starts 'step' after the previous and describes 'span' bases.\\n\\\n\\n\\\nKeyword arguments:\\n\\\n    values: A list of values.\\n\\\n    span:   A span width. This is an integer value and specifies how many bases\\n\\\n            each entry describes. An entry with a start position of 0 and a span\\n\\\n            of 10 describes the first 10 bases.\\n\\\n    step:   A step width. Each subsequent entry begins this number of bases\\n\\\n            after the previous. So if the first entry has a start of 0 and step\\n\\\n            or 30, the second entry will start at 30.\\n\\\n\\n\\\n>>> import pyBigWig\\n\\\n>>> import tempfile\\n\\\n>>> import os\\n\\\n>>> ofile = tempfile.NamedTemporaryFile(delete=False)\\n\\\n>>> oname = ofile.name\\n\\\n>>> ofile.close()\\n\\\n>>> bw = pyBigWig.open(oname, 'w')\\n\\\n>>> bw.addHeader([(\\\"1\\\", 1000000), (\\\"2\\\", 1500000)])\\n\\\n>>> #Add some bedGraph-like entries\\n\\\n>>> bw.addEntries([\\\"1\\\", \\\"1\\\", \\\"1\\\"], [0, 100, 125], ends=[5, 120, 126], values=[0.0, 1.0, 200.0])\\n\\\n>>> #Variable-step entries, the span 500-520, 600-620, and 635-655\\n\\\n>>> bw.addEntries(\\\"1\\\", [500, 600, 635], values=[-2.0, 150.0, 25.0], span=20)\\n\\\n>>> #Fixed-step entries, the bases described are 900-920, 930-950, and 960-980\\n\\\n>>> bw.addEntries(\\\"1\\\", 900, values=[-5.0, -20.0, 25.0], span=20, step=30)\\n\\\n>>> #This only works due to using validate=False. Obviously the file is then corrupt.\\n\\\n>>> bw.addEntries([\\\"1\\\", \\\"1\\\", \\\"1\\\"], [0, 100, 125], ends=[5, 120, 126], values=[0.0, 1.0, 200.0], validate=False)\\n\\\n>>> bw.close()\\n\\\n>>> os.remove(oname)\"},\n    {\"__enter__\", (PyCFunction)pyBwEnter, METH_NOARGS, NULL},\n    {\"__exit__\", (PyCFunction)pyBwClose, METH_VARARGS, NULL},\n    {NULL, NULL, 0, NULL}\n};\n\n#if PY_MAJOR_VERSION >= 3\nstruct pyBigWigmodule_state {\n    PyObject *error;\n};\n\n#define GETSTATE(m) ((struct pyBigWigmodule_state*)PyModule_GetState(m))\n\nstatic PyModuleDef pyBigWigmodule = {\n    PyModuleDef_HEAD_INIT,\n    \"pyBigWig\",\n    \"A python module for bigWig file access\",\n    -1,\n    bwMethods,\n    NULL, NULL, NULL, NULL\n};\n#endif\n\n//Should set tp_dealloc, tp_print, tp_repr, tp_str, tp_members\nstatic PyTypeObject bigWigFile = {\n#if PY_MAJOR_VERSION >= 3\n    PyVarObject_HEAD_INIT(NULL, 0)\n#else\n    PyObject_HEAD_INIT(NULL)\n    0,              /*ob_size*/\n#endif\n    \"pyBigWig.bigWigFile\",     /*tp_name*/\n    sizeof(pyBigWigFile_t),      /*tp_basicsize*/\n    0,                         /*tp_itemsize*/\n    (destructor)pyBwDealloc,     /*tp_dealloc*/\n    0,                         /*tp_print*/\n    0,                         /*tp_getattr*/\n    0,                         /*tp_setattr*/\n    0,                         /*tp_compare*/\n    0,                         /*tp_repr*/\n    0,                         /*tp_as_number*/\n    0,                         /*tp_as_sequence*/\n    0,                         /*tp_as_mapping*/\n    0,                         /*tp_hash*/\n    0,                         /*tp_call*/\n    0,                         /*tp_str*/\n    PyObject_GenericGetAttr, /*tp_getattro*/\n    PyObject_GenericSetAttr, /*tp_setattro*/\n    0,                         /*tp_as_buffer*/\n#if PY_MAJOR_VERSION >= 3\n    Py_TPFLAGS_DEFAULT,        /*tp_flags*/\n#else\n    Py_TPFLAGS_HAVE_CLASS,     /*tp_flags*/\n#endif\n    \"bigWig File\",             /*tp_doc*/\n    0,                         /*tp_traverse*/\n    0,                         /*tp_clear*/\n    0,                         /*tp_richcompare*/\n    0,                         /*tp_weaklistoffset*/\n    0,                         /*tp_iter*/\n    0,                         /*tp_iternext*/\n    bwObjMethods,                 /*tp_methods*/\n    0,                         /*tp_members*/\n    0,                         /*tp_getset*/\n    0,                         /*tp_base*/\n    0,                         /*tp_dict*/\n    0,                         /*tp_descr_get*/\n    0,                         /*tp_descr_set*/\n    0,                         /*tp_dictoffset*/\n    0,                         /*tp_init*/\n    0,                         /*tp_alloc*/\n    0,                         /*tp_new*/\n    0,0,0,0,0,0\n};\n"
  },
  {
    "path": "pyBigWigTest/__init__.py",
    "content": ""
  },
  {
    "path": "pyBigWigTest/test.py",
    "content": "import pyBigWig\nimport tempfile\nimport os\nimport sys\nimport hashlib\nimport numpy as np\n\nclass TestRemote():\n    fname = \"http://raw.githubusercontent.com/dpryan79/pyBigWig/master/pyBigWigTest/test.bw\"\n\n    def doOpen(self):\n        bw = pyBigWig.open(self.fname)\n        assert(bw is not None)\n        return bw\n\n    def doOpenWith(self):\n        with pyBigWig.open(self.fname) as bw:\n            assert(bw.chroms() == {'1': 195471971, '10': 130694993})\n\n    def doChroms(self, bw):\n        assert(bw.chroms() == {'1': 195471971, '10': 130694993})\n        assert(bw.chroms(\"1\") == 195471971)\n        assert(bw.chroms(\"c\") is None)\n\n    def doHeader(self, bw):\n        assert(bw.header() == {'maxVal': 2, 'sumData': 272, 'minVal': 0, 'version': 4, 'sumSquared': 500, 'nLevels': 1, 'nBasesCovered': 154})\n\n    def doStats(self, bw):\n        assert(bw.stats(\"1\", 0, 3) == [0.2000000054637591])\n        assert(bw.stats(\"1\", 0, 3, type=\"max\") == [0.30000001192092896])\n        assert(bw.stats(\"1\",99,200, type=\"max\", nBins=2) == [1.399999976158142, 1.5])\n        assert(bw.stats(\"1\",np.int64(99), np.int64(200), type=\"max\", nBins=2) == [1.399999976158142, 1.5])\n        assert(bw.stats(\"1\") == [1.3351851569281683])\n\n    def doValues(self, bw):\n        assert(bw.values(\"1\", 0, 3) == [0.10000000149011612, 0.20000000298023224, 0.30000001192092896])\n        assert(bw.values(\"1\", np.int64(0), np.int64(3)) == [0.10000000149011612, 0.20000000298023224, 0.30000001192092896])\n        #assert(bw.values(\"1\", 0, 4) == [0.10000000149011612, 0.20000000298023224, 0.30000001192092896, 'nan'])\n\n    def doIntervals(self, bw):\n        assert(bw.intervals(\"1\", 0, 3) == ((0, 1, 0.10000000149011612), (1, 2, 0.20000000298023224), (2, 3, 0.30000001192092896)))\n        assert(bw.intervals(\"1\", np.int64(0), np.int64(3)) == ((0, 1, 0.10000000149011612), (1, 2, 0.20000000298023224), (2, 3, 0.30000001192092896)))\n        assert(bw.intervals(\"1\") == ((0, 1, 0.10000000149011612), (1, 2, 0.20000000298023224), (2, 3, 0.30000001192092896), (100, 150, 1.399999976158142), (150, 151, 1.5)))\n\n    def doSum(self, bw):\n        assert(bw.stats(\"1\", 100, 151, type=\"sum\", nBins=2) == [35.0, 36.5])\n\n    def doWrite(self, bw):\n        ofile = tempfile.NamedTemporaryFile(delete=False)\n        oname = ofile.name\n        ofile.close()\n        bw2 = pyBigWig.open(oname, \"w\")\n        assert(bw2 is not None)\n        #Since this is an unordered dict(), iterating over the items can swap the order!\n        chroms = [(\"1\", bw.chroms(\"1\")), (\"10\", bw.chroms(\"10\"))]\n        assert(len(bw.chroms()) == 2)\n        bw2.addHeader(chroms, maxZooms=1)\n        #Copy the input file\n        for c in chroms:\n            ints = bw.intervals(c[0])\n            chroms2 = []\n            starts = []\n            ends = []\n            values = []\n            for entry in ints:\n                chroms2.append(c[0])\n                starts.append(entry[0])\n                ends.append(entry[1])\n                values.append(entry[2])\n            bw2.addEntries(chroms2, starts, ends=ends, values=values)\n        bw2.close()\n        #Ensure that the copied file has the same entries and max/min/etc.\n        bw2 = pyBigWig.open(oname)\n        assert(bw.header() == bw2.header())\n        assert(bw.chroms() == bw2.chroms())\n        for c in chroms:\n            ints1 = bw.intervals(c[0])\n            ints2 = bw2.intervals(c[0])\n            assert(ints1 == ints2)\n        bw.close()\n        bw2.close()\n        #Clean up\n        os.remove(oname)\n\n    def doWrite2(self):\n        '''\n        Test all three modes of storing entries. Also test to ensure that we get error messages when doing something silly\n\n        This is a modified version of the writing example from libBigWig\n        '''\n        chroms = [\"1\"]*6\n        starts = [0, 100, 125, 200, 220, 230, 500, 600, 625, 700, 800, 850]\n        ends = [5, 120, 126, 205, 226, 231]\n        values = [0.0, 1.0, 200.0, -2.0, 150.0, 25.0, 0.0, 1.0, 200.0, -2.0, 150.0, 25.0, -5.0, -20.0, 25.0, -5.0, -20.0, 25.0]\n        ofile = tempfile.NamedTemporaryFile(delete=False)\n        oname = ofile.name\n        ofile.close()\n        bw = pyBigWig.open(oname, \"w\")\n        bw.addHeader([(\"1\", 1000000), (\"2\", 1500000)])\n\n        #Intervals\n        bw.addEntries(chroms[0:3], starts[0:3], ends=ends[0:3], values=values[0:3])\n        bw.addEntries(chroms[3:6], starts[3:6], ends=ends[3:6], values=values[3:6])\n\n        #IntervalSpans\n        bw.addEntries(\"1\", starts[6:9], values=values[6:9], span=20)\n        bw.addEntries(\"1\", starts[9:12], values=values[9:12], span=20)\n\n        #IntervalSpanSteps, this should instead take an int\n        bw.addEntries(\"1\", 900, values=values[12:15], span=20, step=30)\n        bw.addEntries(\"1\", 990, values=values[15:18], span=20, step=30)\n\n        #Attempt to add incorrect values. These MUST raise an exception\n        try:\n            bw.addEntries(chroms[0:3], starts[0:3], ends=ends[0:3], values=values[0:3])\n            assert(1==0)\n        except RuntimeError:\n            pass\n        try:\n            bw.addEntries(\"1\", starts[6:9], values=values[6:9], span=20)\n            assert(1==0)\n        except RuntimeError:\n            pass\n        try:\n            bw.addEntries(\"3\", starts[6:9], values=values[6:9], span=20)\n            assert(1==0)\n        except RuntimeError:\n            pass\n        try:\n            bw.addEntries(\"1\", 900, values=values[12:15], span=20, step=30)\n            assert(1==0)\n        except RuntimeError:\n            pass\n\n        #Add a few intervals on a new chromosome\n        bw.addEntries([\"2\"]*3, starts[0:3], ends=ends[0:3], values=values[0:3])\n        bw.close()\n        #check md5sum, this is the simplest method to check correctness\n        h = hashlib.md5(open(oname, \"rb\").read()).hexdigest()\n        assert(h==\"ef104f198c6ce8310acc149d0377fc16\")\n        #Clean up\n        os.remove(oname)\n\n    def doWriteEmpty(self):\n        ofile = tempfile.NamedTemporaryFile(delete=False)\n        oname = ofile.name\n        ofile.close()\n        bw = pyBigWig.open(oname, \"w\")\n        bw.addHeader([(\"1\", 1000000), (\"2\", 1500000)])\n        bw.close()\n\n        #check md5sum\n        h = hashlib.md5(open(oname, \"rb\").read()).hexdigest()\n        assert(h==\"361c600e5badf0b45d819552a7822937\")\n\n        #Ensure we can open and get reasonable results\n        bw = pyBigWig.open(oname)\n        assert(bw.chroms() == {'1': 1000000, '2': 1500000})\n        assert(bw.intervals(\"1\") == None)\n        assert(bw.values(\"1\", 0, 1000000) == [])\n        assert(bw.stats(\"1\", 0, 1000000, nBins=2) == [None, None])\n        bw.close()\n\n        #Clean up\n        os.remove(oname)\n\n    def doWriteNumpy(self):\n        ofile = tempfile.NamedTemporaryFile(delete=False)\n        oname = ofile.name\n        ofile.close()\n        bw = pyBigWig.open(oname, \"w\")\n        bw.addHeader([(\"chr1\", 100), (\"chr2\", 150), (\"chr3\", 200), (\"chr4\", 250)])\n        chroms = np.array([\"chr1\"] * 2 + [\"chr2\"] * 2 + [\"chr3\"] * 2 + [\"chr4\"] * 2)\n        starts = np.array([0, 10, 40, 50, 60, 70, 80, 90], dtype=np.int64)\n        ends = np.array([5, 15, 45, 55, 65, 75, 85, 95], dtype=np.int64)\n        values0 = np.array(np.random.random_sample(8), dtype=np.float64)\n        bw.addEntries(chroms, starts, ends=ends, values=values0)\n        bw.close()\n\n        vals = [(x, y, z) for x, y, z in zip(starts, ends, values0)]\n        bw = pyBigWig.open(oname)\n        assert(bw.chroms() == {'chr1': 100, 'chr2': 150, 'chr3': 200, 'chr4': 250})\n        for idx1, chrom in enumerate([\"chr1\", \"chr2\", \"chr3\", \"chr4\"]):\n            for idx2, tup in enumerate(bw.intervals(chrom)):\n                assert(tup[0] == starts[2 * idx1 + idx2])\n                assert(tup[1] == ends[2 * idx1 + idx2])\n                assert(np.isclose(tup[2], values0[2 * idx1 + idx2]))\n        bw.close()\n\n        #Clean up\n        os.remove(oname)\n\n    def testAll(self):\n        bw = self.doOpen()\n        self.doChroms(bw)\n        if not self.fname.startswith(\"http\"):\n            self.doHeader(bw)\n            self.doStats(bw)\n            self.doSum(bw)\n            self.doValues(bw)\n            self.doIntervals(bw)\n            self.doWrite(bw)\n            self.doOpenWith()\n            self.doWrite2()\n            self.doWriteEmpty()\n            self.doWriteNumpy()\n        bw.close()\n\nclass TestLocal():\n    def testFoo(self):\n        blah = TestRemote()\n        blah.fname = os.path.dirname(pyBigWig.__file__) + \"/pyBigWigTest/test.bw\"\n        blah.testAll()\n\nclass TestBigBed():\n    def testBigBed(self):\n        fname = os.path.dirname(pyBigWig.__file__) + \"/pyBigWigTest/test.bigBed\"\n        bb = pyBigWig.open(fname)\n        assert(bb is not None)\n        assert(bb.isBigWig() == 0)\n        assert(bb.isBigBed() == 1)\n        SQL = \"\"\"table RnaElements \n\"BED6 + 3 scores for RNA Elements data \"\n    (\n    string chrom;      \"Reference sequence chromosome or scaffold\"\n    uint   chromStart; \"Start position in chromosome\"\n    uint   chromEnd;   \"End position in chromosome\"\n    string name;       \"Name of item\"\n    uint   score;      \"Normalized score from 0-1000\"\n    char[1] strand;    \"+ or - or . for unknown\"\n    float level;       \"Expression level such as RPKM or FPKM. Set to -1 for no data.\"\n    float signif;      \"Statistical significance such as IDR. Set to -1 for no data.\"\n    uint score2;       \"Additional measurement/count e.g. number of reads. Set to 0 for no data.\"\n    )\n\"\"\"\n        output = bb.SQL()\n        if isinstance(output, bytes):\n            output = output.decode('ASCII')\n        assert(output == SQL)\n        o = bb.entries('chr1',10000000,10020000)\n        expected = [(10009333, 10009640, '61035\\t130\\t-\\t0.026\\t0.42\\t404'), (10014007, 10014289, '61047\\t136\\t-\\t0.029\\t0.42\\t404'), (10014373, 10024307, '61048\\t630\\t-\\t5.420\\t0.00\\t2672399')]\n        assert(o == expected)\n        o = bb.entries('chr1',np.int64(10000000),np.int64(10020000))\n        assert(o == expected)\n        bb.close()\n\nclass TestNumpy():\n    def testNumpy(self):\n        import os\n        if pyBigWig.numpy == 0:\n            return 0\n        import numpy as np\n\n        bw = pyBigWig.open(\"/tmp/delete.bw\", \"w\")\n        bw.addHeader([(\"1\", 1000)], maxZooms=0)\n        # Type 0\n        chroms = np.array([\"1\"] * 10)\n        starts = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90], dtype=np.int64)\n        ends = np.array([5, 15, 25, 35, 45, 55, 65, 75, 85, 95], dtype=np.int64)\n        values0 = np.array(np.random.random_sample(10), dtype=np.float64)\n        bw.addEntries(chroms, starts, ends=ends, values=values0)\n\n        starts = np.array([100, 110, 120, 130, 140, 150, 160, 170, 180, 190], dtype=np.int64)\n        ends = np.array([105, 115, 125, 135, 145, 155, 165, 175, 185, 195], dtype=np.int64)\n        values1 = np.array(np.random.random_sample(10), dtype=np.float64)\n        bw.addEntries(chroms, starts, ends=ends, values=values1)\n\n        # Type 1, single chrom, multiple starts/values, single span\n        starts = np.array([200, 210, 220, 230, 240, 250, 260, 270, 280, 290], dtype=np.int64)\n        values2 = np.array(np.random.random_sample(10), dtype=np.float64)\n        bw.addEntries(\"1\", starts, span=np.int64(8), values=values2)\n\n        starts = np.array([300, 310, 320, 330, 340, 350, 360, 370, 380, 390], dtype=np.int64)\n        values3 = np.array(np.random.random_sample(10), dtype=np.float64)\n        bw.addEntries(\"1\", starts, span=np.int64(8), values=values3)\n\n        # Type 2, single chrom/start/span/step, multiple values\n        values4 = np.array(np.random.random_sample(10), dtype=np.float64)\n        bw.addEntries(\"1\", np.int64(400), span=np.int64(8), step=np.int64(2), values=values4)\n\n        values5 = np.array(np.random.random_sample(10), dtype=np.float64)\n        bw.addEntries(\"1\", np.int64(500), span=np.int64(8), step=np.int64(2), values=values5)\n\n        bw.close()\n\n        bw = pyBigWig.open(\"/tmp/delete.bw\")\n        assert(bw is not None)\n\n        def compy(start, v2):\n            v = []\n            for t in bw.intervals(\"1\", start, start + 100):\n                v.append(t[2])\n            v = np.array(v)\n            assert(np.all(np.abs(v - v2) < 1e-5))\n\n        compy(0, values0)\n        compy(100, values1)\n        compy(200, values2)\n        compy(300, values3)\n        compy(400, values4)\n        compy(500, values5)\n\n        # Get values as a numpy array\n        foo = bw.values(\"1\", 0, 100, numpy=False)\n        assert(isinstance(foo, list))\n        foo = bw.values(\"1\", 0, 100, numpy=True)\n        assert(isinstance(foo, np.ndarray))\n\n        bw.close()\n        os.remove(\"/tmp/delete.bw\")\n\n    def testNumpyValues(self):\n        if pyBigWig.numpy == 0:\n            return 0\n        import numpy as np\n\n        fname = \"http://raw.githubusercontent.com/dpryan79/pyBigWig/master/pyBigWigTest/test.bw\"\n        bw = pyBigWig.open(fname, \"r\")\n\n        assert np.allclose(\n            bw.values(\"1\", 0, 20, numpy=True),\n            np.array(bw.values(\"1\", 0, 20), dtype=np.float32),\n            equal_nan=True\n        )\n\n        assert np.allclose(\n            bw.stats(\"1\", 0, 20, \"mean\", 5, numpy=True),\n            np.array(bw.stats(\"1\", 0, 20, \"mean\", 5), dtype=np.float64),\n            equal_nan=True\n        )\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nbuild-backend = \"setuptools.build_meta\"\nrequires = [\"numpy >= 2.0.0\", \"setuptools\", \"setuptools-scm\"]\n\n[project]\nauthors = [{name = \"Devon P. Ryan\", email = \"dryan79@gmail.com\"}]\nclassifiers = [\n  \"Development Status :: 5 - Production/Stable\",\n  \"Intended Audience :: Developers\",\n  \"License :: OSI Approved\",\n  \"Programming Language :: C\",\n  \"Programming Language :: Python\",\n  \"Programming Language :: Python :: 3\",\n  \"Programming Language :: Python :: 3.9\",\n  \"Programming Language :: Python :: Implementation :: CPython\",\n  \"Operating System :: POSIX\",\n  \"Operating System :: Unix\",\n  \"Operating System :: MacOS\",\n]\ndescription = \"A package for accessing bigWig files using libBigWig\"\nkeywords = [\"bioinformatics\", \"bigWig\", \"bigBed\"]\nname = \"pyBigWig\"\nversion = \"0.3.25\"\nreadme = \"README.md\"\nrequires-python = \">=3.9\"\n\n[project.license]\ntext = \"MIT\"\n\n[project.urls]\n\"Bug Tracker\" = \"https://github.com/deeptools/pyBigWig/issues\"\n\"Download\" = \"https://pypi.python.org/pypi/pyBigWig\"\n\"Homepage\" = \"https://github.com/deeptools/pyBigWig\"\n\n[tool.setuptools]\n# Override setuptools autodiscovery algorithm\n# Only include package test data/source for wheel distribution\ninclude-package-data = true\npackages = [\"pyBigWigTest\"]\n\n# Enable version inference from scm\n[tool.setuptools_scm]\n\n# Target only minimum CPython version 3.9 on linux for wheel build\n[tool.cibuildwheel]\nskip = \"pp* cp38-* *-manylinux_i686 *_ppc64le *_s390x *-musllinux_x86_64 *-musllinux_i686\"\n\n[tool.cibuildwheel.linux]\nmanylinux-x86_64-image = \"manylinux2014\"\n"
  },
  {
    "path": "setup.cfg",
    "content": "# This is required for setuptools to name the wheel with the correct\n# minimum python abi version\n# Commenting this out, since this ends up breaking wheels on anything except python 3.7\n#[bdist_wheel]\n#py-limited-api = cp37\n"
  },
  {
    "path": "setup.py",
    "content": "#!/usr/bin/env python\nfrom setuptools import setup, Extension\nfrom distutils import sysconfig\nfrom pathlib import Path\nimport subprocess\nimport glob\nimport sys\n\nsrcs = [x for x in \n    glob.glob(\"libBigWig/*.c\")]\nsrcs.append(\"pyBigWig.c\")\n\nlibs=[\"m\", \"z\"]\n\n# do not link to python on mac, see https://github.com/deeptools/pyBigWig/issues/58\nif 'dynamic_lookup' not in (sysconfig.get_config_var('LDSHARED') or ''):\n    if sysconfig.get_config_vars('BLDLIBRARY') is not None:\n        #Note the \"-l\" prefix!\n        for e in sysconfig.get_config_vars('BLDLIBRARY')[0].split():\n            if e[0:2] == \"-l\":\n                libs.append(e[2:])\n    elif sys.version_info[0] >= 3 and sys.version_info[1] >= 3:\n        libs.append(\"python%i.%im\" % (sys.version_info[0], sys.version_info[1]))\n    else:\n        libs.append(\"python%i.%i\" % (sys.version_info[0], sys.version_info[1]))\n\nadditional_libs = [sysconfig.get_config_var(\"LIBDIR\"), sysconfig.get_config_var(\"LIBPL\")]\n\ndefines = []\ntry:\n    foo, _ = subprocess.Popen(['curl-config', '--libs'], stdout=subprocess.PIPE).communicate()\n    libs.append(\"curl\")\n    foo = foo.decode().strip().split()\nexcept:\n    foo = []\n    defines.append(('NOCURL', None))\n    sys.stderr.write(\"Either libcurl isn't installed, it didn't come with curl-config, or curl-config isn't in your $PATH. pyBigWig will be installed without support for remote files.\\n\")\n\nfor v in foo:\n    if v[0:2] == '-L':\n        additional_libs.append(v[2:])\n\ninclude_dirs = ['libBigWig', sysconfig.get_config_var(\"INCLUDEPY\")]\n\n# Add numpy build information if numpy is installed as a package\ntry:\n    import numpy\n    defines.extend([('WITHNUMPY', None), ('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')])\n\n    # Ref: https://numpy.org/doc/stable/reference/c-api/coremath.html#linking-against-the-core-math-library-in-an-extension\n    numpy_include_dir = numpy.get_include()\n    numpy_library_dir = str(Path(numpy_include_dir) / '..' / 'lib')\n\n    include_dirs.append(numpy_include_dir)\n    additional_libs.append(numpy_library_dir)\n    libs.append('npymath')\n# Silently ignore a failed import of numpy\nexcept ImportError:\n    pass\n\nmodule1 = Extension('pyBigWig',\n                    sources = srcs,\n                    libraries = libs,\n                    library_dirs = additional_libs, \n                    define_macros = defines,\n                    include_dirs = include_dirs)\n\nsetup(\n    ext_modules=[module1]\n)\n"
  }
]