Commit message: Security fixes: expect final changes for release 1.75.3.
* Fixed a debian security issue with fscanf() reading a string with
  possible buffer overflow.
* There were also a few similar situations with sscanf().
CVE: CVE-2018-7186
CWE: CWE-119
Vulnerability description: Leptonica before 1.75.3 does not limit the number of characters in a %s format argument to fscanf or sscanf, which allows remote attackers to cause a denial of service (stack-based buffer overflow) or possibly have unspecified other impact via a long string, as demonstrated by the gplotRead and ptaReadStream functions.

Project: leptonica
File: gplot.c

gplotDestroy(GPLOT  **pgplot)
{
GPLOT  *gplot;

    PROCNAME("gplotDestroy");

    if (pgplot == NULL) {
        L_WARNING("ptr address is null!\n", procName);
        return;
    }

    if ((gplot = *pgplot) == NULL)
        return;

    LEPT_FREE(gplot->rootname);
    LEPT_FREE(gplot->cmdname);
    sarrayDestroy(&gplot->cmddata);
    sarrayDestroy(&gplot->datanames);
    sarrayDestroy(&gplot->plotdata);
    sarrayDestroy(&gplot->plottitles);
    numaDestroy(&gplot->plotstyles);
    LEPT_FREE(gplot->outname);
    if (gplot->title)
        LEPT_FREE(gplot->title);
    if (gplot->xlabel)
        LEPT_FREE(gplot->xlabel);
    if (gplot->ylabel)
        LEPT_FREE(gplot->ylabel);

    LEPT_FREE(gplot);
    *pgplot = NULL;
    return;
}

Project: leptonica
File: gplot.c

gplotGenDataFiles(GPLOT  *gplot)
{
char    *plotdata, *dataname;
l_int32  i, nplots;
FILE    *fp;

    PROCNAME("gplotGenDataFiles");

    if (!gplot)
        return ERROR_INT("gplot not defined", procName, 1);

    nplots = sarrayGetCount(gplot->datanames);
    for (i = 0; i < nplots; i++) {
        plotdata = sarrayGetString(gplot->plotdata, i, L_NOCOPY);
        dataname = sarrayGetString(gplot->datanames, i, L_NOCOPY);
        if ((fp = fopen(dataname, "w")) == NULL)
            return ERROR_INT("datafile stream not opened", procName, 1);
        fwrite(plotdata, 1, strlen(plotdata), fp);
        fclose(fp);
    }

    return 0;
}

Project: leptonica
File: gplot.c

gplotSetScaling(GPLOT   *gplot,
                l_int32  scaling)
{
    PROCNAME("gplotSetScaling");

    if (!gplot)
        return ERROR_INT("gplot not defined", procName, 1);
    if (scaling != GPLOT_LINEAR_SCALE &&
        scaling != GPLOT_LOG_SCALE_X &&
        scaling != GPLOT_LOG_SCALE_Y &&
        scaling != GPLOT_LOG_SCALE_X_Y)
        return ERROR_INT("invalid gplot scaling", procName, 1);
    gplot->scaling = scaling;
    return 0;
}

Project: leptonica
File: gplot.c

gplotSimple1(NUMA        *na,
             l_int32      outformat,
             const char  *outroot,
             const char  *title)
{
    return gplotSimpleXY1(NULL, na, GPLOT_LINES, outformat, outroot, title);
}

Project: leptonica
File: gplot.c

gplotSimple2(NUMA        *na1,
             NUMA        *na2,
             l_int32      outformat,
             const char  *outroot,
             const char  *title)
{
    return gplotSimpleXY2(NULL, na1, na2, GPLOT_LINES,
                          outformat, outroot, title);
}

Project: leptonica
File: gplot.c

gplotSimpleN(NUMAA       *naa,
             l_int32      outformat,
             const char  *outroot,
             const char  *title)
{
    return gplotSimpleXYN(NULL, naa, GPLOT_LINES, outformat, outroot, title);
}

Project: leptonica
File: gplot.c

gplotSimpleXY1(NUMA        *nax,
               NUMA        *nay,
               l_int32      plotstyle,
               l_int32      outformat,
               const char  *outroot,
               const char  *title)
{
GPLOT  *gplot;

    PROCNAME("gplotSimpleXY1");

    if (!nay)
        return ERROR_INT("nay not defined", procName, 1);
    if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
        return ERROR_INT("invalid plotstyle", procName, 1);
    if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
        outformat != GPLOT_EPS && outformat != GPLOT_LATEX)
        return ERROR_INT("invalid outformat", procName, 1);
    if (!outroot)
        return ERROR_INT("outroot not specified", procName, 1);

    if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
        return ERROR_INT("gplot not made", procName, 1);
    gplotAddPlot(gplot, nax, nay, plotstyle, NULL);
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    return 0;
}

Project: leptonica
File: gplot.c

gplotSimpleXY2(NUMA        *nax,
               NUMA        *nay1,
               NUMA        *nay2,
               l_int32      plotstyle,
               l_int32      outformat,
               const char  *outroot,
               const char  *title)
{
GPLOT  *gplot;

    PROCNAME("gplotSimpleXY2");

    if (!nay1 || !nay2)
        return ERROR_INT("nay1 and nay2 not both defined", procName, 1);
    if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
        return ERROR_INT("invalid plotstyle", procName, 1);
    if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
        outformat != GPLOT_EPS && outformat != GPLOT_LATEX)
        return ERROR_INT("invalid outformat", procName, 1);
    if (!outroot)
        return ERROR_INT("outroot not specified", procName, 1);

    if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
        return ERROR_INT("gplot not made", procName, 1);
    gplotAddPlot(gplot, nax, nay1, plotstyle, NULL);
    gplotAddPlot(gplot, nax, nay2, plotstyle, NULL);
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    return 0;
}

Project: leptonica
File: gplot.c

gplotSimpleXYN(NUMA        *nax,
               NUMAA       *naay,
               l_int32      plotstyle,
               l_int32      outformat,
               const char  *outroot,
               const char  *title)
{
l_int32  i, n;
GPLOT   *gplot;
NUMA    *nay;

    PROCNAME("gplotSimpleXYN");

    if (!naay)
        return ERROR_INT("naay not defined", procName, 1);
    if ((n = numaaGetCount(naay)) == 0)
        return ERROR_INT("no numa in array", procName, 1);
    if (plotstyle < 0 || plotstyle >= NUM_GPLOT_STYLES)
        return ERROR_INT("invalid plotstyle", procName, 1);
    if (outformat != GPLOT_PNG && outformat != GPLOT_PS &&
        outformat != GPLOT_EPS && outformat != GPLOT_LATEX)
        return ERROR_INT("invalid outformat", procName, 1);
    if (!outroot)
        return ERROR_INT("outroot not specified", procName, 1);

    if ((gplot = gplotCreate(outroot, outformat, title, NULL, NULL)) == 0)
        return ERROR_INT("gplot not made", procName, 1);
    for (i = 0; i < n; i++) {
        nay = numaaGetNuma(naay, i, L_CLONE);
        gplotAddPlot(gplot, nax, nay, plotstyle, NULL);
        numaDestroy(&nay);
    }
    gplotMakeOutput(gplot);
    gplotDestroy(&gplot);
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaAddPt(PTA       *pta,
         l_float32  x,
         l_float32  y)
{
l_int32  n;

    PROCNAME("ptaAddPt");

    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);

    n = pta->n;
    if (n >= pta->nalloc)
        ptaExtendArrays(pta);
    pta->x[n] = x;
    pta->y[n] = y;
    pta->n++;

    return 0;
}

Project: leptonica
File: ptabasic.c

ptaChangeRefcount(PTA     *pta,
                  l_int32  delta)
{
    PROCNAME("ptaChangeRefcount");

    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    pta->refcount += delta;
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaClone(PTA  *pta)
{
    PROCNAME("ptaClone");

    if (!pta)
        return (PTA *)ERROR_PTR("pta not defined", procName, NULL);

    ptaChangeRefcount(pta, 1);
    return pta;
}

Project: leptonica
File: ptabasic.c

ptaCopy(PTA  *pta)
{
l_int32    i;
l_float32  x, y;
PTA       *npta;

    PROCNAME("ptaCopy");

    if (!pta)
        return (PTA *)ERROR_PTR("pta not defined", procName, NULL);

    if ((npta = ptaCreate(pta->nalloc)) == NULL)
        return (PTA *)ERROR_PTR("npta not made", procName, NULL);

    for (i = 0; i < pta->n; i++) {
        ptaGetPt(pta, i, &x, &y);
        ptaAddPt(npta, x, y);
    }

    return npta;
}

Project: leptonica
File: ptabasic.c

ptaCopyRange(PTA     *ptas,
             l_int32  istart,
             l_int32  iend)
{
l_int32  n, i, x, y;
PTA     *ptad;

    PROCNAME("ptaCopyRange");

    if (!ptas)
        return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
    n = ptaGetCount(ptas);
    if (istart < 0)
        istart = 0;
    if (istart >= n)
        return (PTA *)ERROR_PTR("istart out of bounds", procName, NULL);
    if (iend <= 0 || iend >= n)
        iend = n - 1;
    if (istart > iend)
        return (PTA *)ERROR_PTR("istart > iend; no pts", procName, NULL);

    if ((ptad = ptaCreate(iend - istart + 1)) == NULL)
        return (PTA *)ERROR_PTR("ptad not made", procName, NULL);
    for (i = istart; i <= iend; i++) {
        ptaGetIPt(ptas, i, &x, &y);
        ptaAddPt(ptad, x, y);
    }

    return ptad;
}

Project: leptonica
File: ptabasic.c

ptaCreate(l_int32  n)
{
PTA  *pta;

    PROCNAME("ptaCreate");

    if (n <= 0)
        n = INITIAL_PTR_ARRAYSIZE;

    pta = (PTA *)LEPT_CALLOC(1, sizeof(PTA));
    pta->n = 0;
    pta->nalloc = n;
    ptaChangeRefcount(pta, 1);  /* sets to 1 */

    pta->x = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
    pta->y = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32));
    if (!pta->x || !pta->y) {
        ptaDestroy(&pta);
        return (PTA *)ERROR_PTR("x and y arrays not both made", procName, NULL);
    }

    return pta;
}

Project: leptonica
File: ptabasic.c

ptaGetArrays(PTA    *pta,
             NUMA  **pnax,
             NUMA  **pnay)
{
l_int32  i, n;
NUMA    *nax, *nay;

    PROCNAME("ptaGetArrays");

    if (!pnax && !pnay)
        return ERROR_INT("no output requested", procName, 1);
    if (pnax) *pnax = NULL;
    if (pnay) *pnay = NULL;
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    if ((n = ptaGetCount(pta)) == 0)
        return ERROR_INT("pta is empty", procName, 1);

    if (pnax) {
        if ((nax = numaCreate(n)) == NULL)
            return ERROR_INT("nax not made", procName, 1);
        *pnax = nax;
        for (i = 0; i < n; i++)
            nax->array[i] = pta->x[i];
        nax->n = n;
    }
    if (pnay) {
        if ((nay = numaCreate(n)) == NULL)
            return ERROR_INT("nay not made", procName, 1);
        *pnay = nay;
        for (i = 0; i < n; i++)
            nay->array[i] = pta->y[i];
        nay->n = n;
    }
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaGetCount(PTA  *pta)
{
    PROCNAME("ptaGetCount");

    if (!pta)
        return ERROR_INT("pta not defined", procName, 0);

    return pta->n;
}

Project: leptonica
File: ptabasic.c

ptaGetIPt(PTA      *pta,
          l_int32   index,
          l_int32  *px,
          l_int32  *py)
{
    PROCNAME("ptaGetIPt");

    if (px) *px = 0;
    if (py) *py = 0;
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    if (index < 0 || index >= pta->n)
        return ERROR_INT("invalid index", procName, 1);

    if (px) *px = (l_int32)(pta->x[index] + 0.5);
    if (py) *py = (l_int32)(pta->y[index] + 0.5);
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaGetPt(PTA        *pta,
         l_int32     index,
         l_float32  *px,
         l_float32  *py)
{
    PROCNAME("ptaGetPt");

    if (px) *px = 0;
    if (py) *py = 0;
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    if (index < 0 || index >= pta->n)
        return ERROR_INT("invalid index", procName, 1);

    if (px) *px = pta->x[index];
    if (py) *py = pta->y[index];
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaGetRefcount(PTA  *pta)
{
    PROCNAME("ptaGetRefcount");

    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    return pta->refcount;
}

Project: leptonica
File: ptabasic.c

ptaInsertPt(PTA     *pta,
            l_int32  index,
            l_int32  x,
            l_int32  y)
{
l_int32  i, n;

    PROCNAME("ptaInsertPt");

    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    n = ptaGetCount(pta);
    if (index < 0 || index > n)
        return ERROR_INT("index not in {0...n}", procName, 1);

    if (n > pta->nalloc)
        ptaExtendArrays(pta);
    pta->n++;
    for (i = n; i > index; i--) {
        pta->x[i] = pta->x[i - 1];
        pta->y[i] = pta->y[i - 1];
    }
    pta->x[index] = x;
    pta->y[index] = y;
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaRead(const char  *filename)
{
FILE  *fp;
PTA   *pta;

    PROCNAME("ptaRead");

    if (!filename)
        return (PTA *)ERROR_PTR("filename not defined", procName, NULL);

    if ((fp = fopenReadStream(filename)) == NULL)
        return (PTA *)ERROR_PTR("stream not opened", procName, NULL);
    pta = ptaReadStream(fp);
    fclose(fp);
    if (!pta)
        return (PTA *)ERROR_PTR("pta not read", procName, NULL);
    return pta;
}

Project: leptonica
File: ptabasic.c

ptaReadMem(const l_uint8  *data,
           size_t          size)
{
FILE  *fp;
PTA   *pta;

    PROCNAME("ptaReadMem");

    if (!data)
        return (PTA *)ERROR_PTR("data not defined", procName, NULL);
    if ((fp = fopenReadFromMemory(data, size)) == NULL)
        return (PTA *)ERROR_PTR("stream not opened", procName, NULL);

    pta = ptaReadStream(fp);
    fclose(fp);
    if (!pta) L_ERROR("pta not read\n", procName);
    return pta;
}

Project: leptonica
File: ptabasic.c

ptaRemovePt(PTA     *pta,
            l_int32  index)
{
l_int32  i, n;

    PROCNAME("ptaRemovePt");

    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    n = ptaGetCount(pta);
    if (index < 0 || index >= n)
        return ERROR_INT("index not in {0...n - 1}", procName, 1);

        /* Remove the point */
    for (i = index + 1; i < n; i++) {
        pta->x[i - 1] = pta->x[i];
        pta->y[i - 1] = pta->y[i];
    }
    pta->n--;
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaSetPt(PTA       *pta,
         l_int32    index,
         l_float32  x,
         l_float32  y)
{
    PROCNAME("ptaSetPt");

    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    if (index < 0 || index >= pta->n)
        return ERROR_INT("invalid index", procName, 1);

    pta->x[index] = x;
    pta->y[index] = y;
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaWrite(const char  *filename,
         PTA         *pta,
         l_int32      type)
{
l_int32  ret;
FILE    *fp;

    PROCNAME("ptaWrite");

    if (!filename)
        return ERROR_INT("filename not defined", procName, 1);
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);

    if ((fp = fopenWriteStream(filename, "w")) == NULL)
        return ERROR_INT("stream not opened", procName, 1);
    ret = ptaWriteStream(fp, pta, type);
    fclose(fp);
    if (ret)
        return ERROR_INT("pta not written to stream", procName, 1);
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaWriteMem(l_uint8  **pdata,
            size_t    *psize,
            PTA       *pta,
            l_int32    type)
{
l_int32  ret;
FILE    *fp;

    PROCNAME("ptaWriteMem");

    if (pdata) *pdata = NULL;
    if (psize) *psize = 0;
    if (!pdata)
        return ERROR_INT("&data not defined", procName, 1);
    if (!psize)
        return ERROR_INT("&size not defined", procName, 1);
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);

#if HAVE_FMEMOPEN
    if ((fp = open_memstream((char **)pdata, psize)) == NULL)
        return ERROR_INT("stream not opened", procName, 1);
    ret = ptaWriteStream(fp, pta, type);
#else
    L_INFO("work-around: writing to a temp file\n", procName);
  #ifdef _WIN32
    if ((fp = fopenWriteWinTempfile()) == NULL)
        return ERROR_INT("tmpfile stream not opened", procName, 1);
  #else
    if ((fp = tmpfile()) == NULL)
        return ERROR_INT("tmpfile stream not opened", procName, 1);
  #endif  /* _WIN32 */
    ret = ptaWriteStream(fp, pta, type);
    rewind(fp);
    *pdata = l_binaryReadStream(fp, psize);
#endif  /* HAVE_FMEMOPEN */
    fclose(fp);
    return ret;
}

Project: leptonica
File: ptabasic.c

ptaWriteStream(FILE    *fp,
               PTA     *pta,
               l_int32  type)
{
l_int32    i, n, ix, iy;
l_float32  x, y;

    PROCNAME("ptaWriteStream");

    if (!fp)
        return ERROR_INT("stream not defined", procName, 1);
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);

    n = ptaGetCount(pta);
    fprintf(fp, "\n Pta Version %d\n", PTA_VERSION_NUMBER);
    if (type == 0)
        fprintf(fp, " Number of pts = %d; format = float\n", n);
    else  /* type == 1 */
        fprintf(fp, " Number of pts = %d; format = integer\n", n);
    for (i = 0; i < n; i++) {
        if (type == 0) {  /* data is float */
            ptaGetPt(pta, i, &x, &y);
            fprintf(fp, "   (%f, %f)\n", x, y);
        } else {   /* data is integer */
            ptaGetIPt(pta, i, &ix, &iy);
            fprintf(fp, "   (%d, %d)\n", ix, iy);
        }
    }

    return 0;
}

Project: leptonica
File: ptabasic.c

ptaaAddPt(PTAA      *ptaa,
          l_int32    ipta,
          l_float32  x,
          l_float32  y)
{
PTA  *pta;

    PROCNAME("ptaaAddPt");

    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);
    if (ipta < 0 || ipta >= ptaa->n)
        return ERROR_INT("index ipta not valid", procName, 1);

    pta = ptaaGetPta(ptaa, ipta, L_CLONE);
    ptaAddPt(pta, x, y);
    ptaDestroy(&pta);
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaaAddPta(PTAA    *ptaa,
           PTA     *pta,
           l_int32  copyflag)
{
l_int32  n;
PTA     *ptac;

    PROCNAME("ptaaAddPta");

    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);

    if (copyflag == L_INSERT) {
        ptac = pta;
    } else if (copyflag == L_COPY) {
        if ((ptac = ptaCopy(pta)) == NULL)
            return ERROR_INT("ptac not made", procName, 1);
    } else if (copyflag == L_CLONE) {
        if ((ptac = ptaClone(pta)) == NULL)
            return ERROR_INT("pta clone not made", procName, 1);
    } else {
        return ERROR_INT("invalid copyflag", procName, 1);
    }

    n = ptaaGetCount(ptaa);
    if (n >= ptaa->nalloc)
        ptaaExtendArray(ptaa);
    ptaa->pta[n] = ptac;
    ptaa->n++;

    return 0;
}

Project: leptonica
File: ptabasic.c

ptaaCreate(l_int32  n)
{
PTAA  *ptaa;

    PROCNAME("ptaaCreate");

    if (n <= 0)
        n = INITIAL_PTR_ARRAYSIZE;

    if ((ptaa = (PTAA *)LEPT_CALLOC(1, sizeof(PTAA))) == NULL)
        return (PTAA *)ERROR_PTR("ptaa not made", procName, NULL);
    ptaa->n = 0;
    ptaa->nalloc = n;
    if ((ptaa->pta = (PTA **)LEPT_CALLOC(n, sizeof(PTA *))) == NULL) {
        ptaaDestroy(&ptaa);
        return (PTAA *)ERROR_PTR("pta ptrs not made", procName, NULL);
    }
    return ptaa;
}

Project: leptonica
File: ptabasic.c

ptaaDestroy(PTAA  **pptaa)
{
l_int32  i;
PTAA    *ptaa;

    PROCNAME("ptaaDestroy");

    if (pptaa == NULL) {
        L_WARNING("ptr address is NULL!\n", procName);
        return;
    }

    if ((ptaa = *pptaa) == NULL)
        return;

    for (i = 0; i < ptaa->n; i++)
        ptaDestroy(&ptaa->pta[i]);
    LEPT_FREE(ptaa->pta);

    LEPT_FREE(ptaa);
    *pptaa = NULL;
    return;
}

Project: leptonica
File: ptabasic.c

ptaaExtendArray(PTAA  *ptaa)
{
    PROCNAME("ptaaExtendArray");

    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);

    if ((ptaa->pta = (PTA **)reallocNew((void **)&ptaa->pta,
                             sizeof(PTA *) * ptaa->nalloc,
                             2 * sizeof(PTA *) * ptaa->nalloc)) == NULL)
        return ERROR_INT("new ptr array not returned", procName, 1);

    ptaa->nalloc = 2 * ptaa->nalloc;
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaaGetPta(PTAA    *ptaa,
           l_int32  index,
           l_int32  accessflag)
{
    PROCNAME("ptaaGetPta");

    if (!ptaa)
        return (PTA *)ERROR_PTR("ptaa not defined", procName, NULL);
    if (index < 0 || index >= ptaa->n)
        return (PTA *)ERROR_PTR("index not valid", procName, NULL);

    if (accessflag == L_COPY)
        return ptaCopy(ptaa->pta[index]);
    else if (accessflag == L_CLONE)
        return ptaClone(ptaa->pta[index]);
    else
        return (PTA *)ERROR_PTR("invalid accessflag", procName, NULL);
}

Project: leptonica
File: ptabasic.c

ptaaReadMem(const l_uint8  *data,
            size_t          size)
{
FILE  *fp;
PTAA  *ptaa;

    PROCNAME("ptaaReadMem");

    if (!data)
        return (PTAA *)ERROR_PTR("data not defined", procName, NULL);
    if ((fp = fopenReadFromMemory(data, size)) == NULL)
        return (PTAA *)ERROR_PTR("stream not opened", procName, NULL);

    ptaa = ptaaReadStream(fp);
    fclose(fp);
    if (!ptaa) L_ERROR("ptaa not read\n", procName);
    return ptaa;
}

Project: leptonica
File: ptabasic.c

ptaaReadStream(FILE  *fp)
{
l_int32  i, n, version;
PTA     *pta;
PTAA    *ptaa;

    PROCNAME("ptaaReadStream");

    if (!fp)
        return (PTAA *)ERROR_PTR("stream not defined", procName, NULL);

    if (fscanf(fp, "\nPtaa Version %d\n", &version) != 1)
        return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);
    if (version != PTA_VERSION_NUMBER)
        return (PTAA *)ERROR_PTR("invalid ptaa version", procName, NULL);
    if (fscanf(fp, "Number of Pta = %d\n", &n) != 1)
        return (PTAA *)ERROR_PTR("not a ptaa file", procName, NULL);

    if ((ptaa = ptaaCreate(n)) == NULL)
        return (PTAA *)ERROR_PTR("ptaa not made", procName, NULL);
    for (i = 0; i < n; i++) {
        if ((pta = ptaReadStream(fp)) == NULL) {
            ptaaDestroy(&ptaa);
            return (PTAA *)ERROR_PTR("error reading pta", procName, NULL);
        }
        ptaaAddPta(ptaa, pta, L_INSERT);
    }

    return ptaa;
}

Project: leptonica
File: ptabasic.c

ptaaReplacePta(PTAA    *ptaa,
               l_int32  index,
               PTA     *pta)
{
l_int32  n;

    PROCNAME("ptaaReplacePta");

    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);
    if (!pta)
        return ERROR_INT("pta not defined", procName, 1);
    n = ptaaGetCount(ptaa);
    if (index < 0 || index >= n)
        return ERROR_INT("index not valid", procName, 1);

    ptaDestroy(&ptaa->pta[index]);
    ptaa->pta[index] = pta;
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaaTruncate(PTAA  *ptaa)
{
l_int32  i, n, np;
PTA     *pta;

    PROCNAME("ptaaTruncate");

    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);

    n = ptaaGetCount(ptaa);
    for (i = n - 1; i >= 0; i--) {
        pta = ptaaGetPta(ptaa, i, L_CLONE);
        if (!pta) {
            ptaa->n--;
            continue;
        }
        np = ptaGetCount(pta);
        ptaDestroy(&pta);
        if (np == 0) {
            ptaDestroy(&ptaa->pta[i]);
            ptaa->n--;
        } else {
            break;
        }
    }
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaaWrite(const char  *filename,
          PTAA        *ptaa,
          l_int32      type)
{
l_int32  ret;
FILE    *fp;

    PROCNAME("ptaaWrite");

    if (!filename)
        return ERROR_INT("filename not defined", procName, 1);
    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);

    if ((fp = fopenWriteStream(filename, "w")) == NULL)
        return ERROR_INT("stream not opened", procName, 1);
    ret = ptaaWriteStream(fp, ptaa, type);
    fclose(fp);
    if (ret)
        return ERROR_INT("ptaa not written to stream", procName, 1);
    return 0;
}

Project: leptonica
File: ptabasic.c

ptaaWriteMem(l_uint8  **pdata,
             size_t    *psize,
             PTAA      *ptaa,
             l_int32    type)
{
l_int32  ret;
FILE    *fp;

    PROCNAME("ptaaWriteMem");

    if (pdata) *pdata = NULL;
    if (psize) *psize = 0;
    if (!pdata)
        return ERROR_INT("&data not defined", procName, 1);
    if (!psize)
        return ERROR_INT("&size not defined", procName, 1);
    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);

#if HAVE_FMEMOPEN
    if ((fp = open_memstream((char **)pdata, psize)) == NULL)
        return ERROR_INT("stream not opened", procName, 1);
    ret = ptaaWriteStream(fp, ptaa, type);
#else
    L_INFO("work-around: writing to a temp file\n", procName);
  #ifdef _WIN32
    if ((fp = fopenWriteWinTempfile()) == NULL)
        return ERROR_INT("tmpfile stream not opened", procName, 1);
  #else
    if ((fp = tmpfile()) == NULL)
        return ERROR_INT("tmpfile stream not opened", procName, 1);
  #endif  /* _WIN32 */
    ret = ptaaWriteStream(fp, ptaa, type);
    rewind(fp);
    *pdata = l_binaryReadStream(fp, psize);
#endif  /* HAVE_FMEMOPEN */
    fclose(fp);
    return ret;
}

Project: leptonica
File: ptabasic.c

ptaaWriteStream(FILE    *fp,
                PTAA    *ptaa,
                l_int32  type)
{
l_int32  i, n;
PTA     *pta;

    PROCNAME("ptaaWriteStream");

    if (!fp)
        return ERROR_INT("stream not defined", procName, 1);
    if (!ptaa)
        return ERROR_INT("ptaa not defined", procName, 1);

    n = ptaaGetCount(ptaa);
    fprintf(fp, "\nPtaa Version %d\n", PTA_VERSION_NUMBER);
    fprintf(fp, "Number of Pta = %d\n", n);
    for (i = 0; i < n; i++) {
        pta = ptaaGetPta(ptaa, i, L_CLONE);
        ptaWriteStream(fp, pta, type);
        ptaDestroy(&pta);
    }

    return 0;
}

Project: leptonica
File: sel1.c

create2dIntArray(l_int32  sy,
                 l_int32  sx)
{
l_int32    i, j, success;
l_int32  **array;

    PROCNAME("create2dIntArray");

    if ((array = (l_int32 **)LEPT_CALLOC(sy, sizeof(l_int32 *))) == NULL)
        return (l_int32 **)ERROR_PTR("ptr array not made", procName, NULL);

    success = TRUE;
    for (i = 0; i < sy; i++) {
        if ((array[i] = (l_int32 *)LEPT_CALLOC(sx, sizeof(l_int32))) == NULL) {
            success = FALSE;
            break;
        }
    }
    if (success) return array;

        /* Cleanup after error */
    for (j = 0; j < i; j++)
        LEPT_FREE(array[j]);
    LEPT_FREE(array);
    return (l_int32 **)ERROR_PTR("array not made", procName, NULL);
}

Project: leptonica
File: sel1.c

getCompositeParameters(l_int32   size,
                       l_int32  *psize1,
                       l_int32  *psize2,
                       char    **pnameh1,
                       char    **pnameh2,
                       char    **pnamev1,
                       char    **pnamev2)
{
l_int32  index;

    PROCNAME("selaGetSelnames");

    if (psize1) *psize1 = 0;
    if (psize2) *psize2 = 0;
    if (pnameh1) *pnameh1 = NULL;
    if (pnameh2) *pnameh2 = NULL;
    if (pnamev1) *pnamev1 = NULL;
    if (pnamev2) *pnamev2 = NULL;
    if (size < 2 || size > 63)
        return ERROR_INT("valid size range is {2 ... 63}", procName, 1);
    index = size - 2;
    if (psize1)
        *psize1 = comp_parameter_map[index].size1;
    if (psize2)
        *psize2 = comp_parameter_map[index].size2;
    if (pnameh1)
        *pnameh1 = stringNew(comp_parameter_map[index].selnameh1);
    if (pnameh2)
        *pnameh2 = stringNew(comp_parameter_map[index].selnameh2);
    if (pnamev1)
        *pnamev1 = stringNew(comp_parameter_map[index].selnamev1);
    if (pnamev2)
        *pnamev2 = stringNew(comp_parameter_map[index].selnamev2);
    return 0;
}

Project: leptonica
File: sel1.c

selCopy(SEL  *sel)
{
l_int32  sx, sy, cx, cy, i, j;
SEL     *csel;

    PROCNAME("selCopy");

    if (!sel)
        return (SEL *)ERROR_PTR("sel not defined", procName, NULL);

    if ((csel = (SEL *)LEPT_CALLOC(1, sizeof(SEL))) == NULL)
        return (SEL *)ERROR_PTR("csel not made", procName, NULL);
    selGetParameters(sel, &sy, &sx, &cy, &cx);
    csel->sy = sy;
    csel->sx = sx;
    csel->cy = cy;
    csel->cx = cx;

    if ((csel->data = create2dIntArray(sy, sx)) == NULL) {
        LEPT_FREE(csel);
        return (SEL *)ERROR_PTR("sel data not made", procName, NULL);
    }

    for (i = 0; i < sy; i++)
        for (j = 0; j < sx; j++)
            csel->data[i][j] = sel->data[i][j];

    if (sel->name)
        csel->name = stringNew(sel->name);

    return csel;
}

Project: leptonica
File: sel1.c

selCreate(l_int32      height,
          l_int32      width,
          const char  *name)
{
SEL  *sel;

    PROCNAME("selCreate");

    if ((sel = (SEL *)LEPT_CALLOC(1, sizeof(SEL))) == NULL)
        return (SEL *)ERROR_PTR("sel not made", procName, NULL);
    if (name)
        sel->name = stringNew(name);
    sel->sy = height;
    sel->sx = width;
    if ((sel->data = create2dIntArray(height, width)) == NULL) {
        LEPT_FREE(sel->name);
        LEPT_FREE(sel);
        return (SEL *)ERROR_PTR("data not allocated", procName, NULL);
    }

    return sel;
}

Project: leptonica
File: sel1.c

selCreateComb(l_int32  factor1,
              l_int32  factor2,
              l_int32  direction)
{
l_int32  i, size, z;
SEL     *sel;

    PROCNAME("selCreateComb");

    if (factor1 < 1 || factor2 < 1)
        return (SEL *)ERROR_PTR("factors must be >= 1", procName, NULL);
    if (direction != L_HORIZ && direction != L_VERT)
        return (SEL *)ERROR_PTR("invalid direction", procName, NULL);

    size = factor1 * factor2;
    if (direction == L_HORIZ) {
        sel = selCreate(1, size, NULL);
        selSetOrigin(sel, 0, size / 2);
    } else {
        sel = selCreate(size, 1, NULL);
        selSetOrigin(sel, size / 2, 0);
    }

        /* Lay down the elements of the comb */
    for (i = 0; i < factor2; i++) {
        z = factor1 / 2 + i * factor1;
/*        fprintf(stderr, "i = %d, factor1 = %d, factor2 = %d, z = %d\n",
                        i, factor1, factor2, z); */
        if (direction == L_HORIZ)
            selSetElement(sel, 0, z, SEL_HIT);
        else
            selSetElement(sel, z, 0, SEL_HIT);
    }

    return sel;
}

Project: leptonica
File: sel1.c

selCreateFromColorPix(PIX   *pixs,
                      char  *selname)
{
PIXCMAP  *cmap;
SEL      *sel;
l_int32   hascolor, hasorigin, nohits;
l_int32   w, h, d, i, j, red, green, blue;
l_uint32  pixval;

    PROCNAME("selCreateFromColorPix");

    if (!pixs)
        return (SEL *)ERROR_PTR("pixs not defined", procName, NULL);

    hascolor = FALSE;
    cmap = pixGetColormap(pixs);
    if (cmap)
        pixcmapHasColor(cmap, &hascolor);
    pixGetDimensions(pixs, &w, &h, &d);
    if (hascolor == FALSE && d != 32)
        return (SEL *)ERROR_PTR("pixs has no color", procName, NULL);

    if ((sel = selCreate (h, w, NULL)) == NULL)
        return (SEL *)ERROR_PTR ("sel not made", procName, NULL);
    selSetOrigin (sel, h / 2, w / 2);
    selSetName(sel, selname);

    hasorigin = FALSE;
    nohits = TRUE;
    for (i = 0; i < h; i++) {
        for (j = 0; j < w; j++) {
            pixGetPixel (pixs, j, i, &pixval);

            if (cmap) {
                pixcmapGetColor (cmap, pixval, &red, &green, &blue);
            } else {
                red = GET_DATA_BYTE (&pixval, COLOR_RED);
                green = GET_DATA_BYTE (&pixval, COLOR_GREEN);
                blue = GET_DATA_BYTE (&pixval, COLOR_BLUE);
            }

            if (red < 255 && green < 255 && blue < 255) {
                if (hasorigin)
                    L_WARNING("multiple origins in sel image\n", procName);
                selSetOrigin (sel, i, j);
                hasorigin = TRUE;
            }
            if (!red && green && !blue) {
                nohits = FALSE;
                selSetElement (sel, i, j, SEL_HIT);
            } else if (red && !green && !blue) {
                selSetElement (sel, i, j, SEL_MISS);
            } else if (red && green && blue) {
                selSetElement (sel, i, j, SEL_DONT_CARE);
            } else {
                selDestroy(&sel);
                return (SEL *)ERROR_PTR("invalid color", procName, NULL);
            }
        }
    }

    if (nohits) {
        selDestroy(&sel);
        return (SEL *)ERROR_PTR("no hits in sel", procName, NULL);
    }
    return sel;
}

Project: leptonica
File: sel1.c

selCreateFromPix(PIX         *pix,
                 l_int32      cy,
                 l_int32      cx,
                 const char  *name)
{
SEL      *sel;
l_int32   i, j, w, h, d;
l_uint32  val;

    PROCNAME("selCreateFromPix");

    if (!pix)
        return (SEL *)ERROR_PTR("pix not defined", procName, NULL);
    if (cy < 0 || cx < 0)
        return (SEL *)ERROR_PTR("(cy, cx) not both >= 0", procName, NULL);
    pixGetDimensions(pix, &w, &h, &d);
    if (d != 1)
        return (SEL *)ERROR_PTR("pix not 1 bpp", procName, NULL);

    sel = selCreate(h, w, name);
    selSetOrigin(sel, cy, cx);
    for (i = 0; i < h; i++) {
        for (j = 0; j < w; j++) {
            pixGetPixel(pix, j, i, &val);
            if (val)
                selSetElement(sel, i, j, SEL_HIT);
        }
    }

    return sel;
}

Project: leptonica
File: sel1.c

selCreateFromPta(PTA         *pta,
                 l_int32      cy,
                 l_int32      cx,
                 const char  *name)
{
l_int32  i, n, x, y, w, h;
BOX     *box;
SEL     *sel;

    PROCNAME("selCreateFromPta");

    if (!pta)
        return (SEL *)ERROR_PTR("pta not defined", procName, NULL);
    if (cy < 0 || cx < 0)
        return (SEL *)ERROR_PTR("(cy, cx) not both >= 0", procName, NULL);
    n = ptaGetCount(pta);
    if (n == 0)
        return (SEL *)ERROR_PTR("no pts in pta", procName, NULL);

    box = ptaGetBoundingRegion(pta);
    boxGetGeometry(box, &x, &y, &w, &h);
    boxDestroy(&box);
    if (x < 0 || y < 0)
        return (SEL *)ERROR_PTR("not all x and y >= 0", procName, NULL);

    sel = selCreate(y + h, x + w, name);
    selSetOrigin(sel, cy, cx);
    for (i = 0; i < n; i++) {
        ptaGetIPt(pta, i, &x, &y);
        selSetElement(sel, y, x, SEL_HIT);
    }

    return sel;
}

Project: leptonica
File: sel1.c

selCreateFromSArray(SARRAY  *sa,
                    l_int32  first,
                    l_int32  last)
{
char     ch;
char    *name, *line;
l_int32  n, len, i, w, h, y, x;
SEL     *sel;

    PROCNAME("selCreateFromSArray");

    if (!sa)
        return (SEL *)ERROR_PTR("sa not defined", procName, NULL);
    n = sarrayGetCount(sa);
    if (first < 0 || first >= n || last <= first || last >= n)
        return (SEL *)ERROR_PTR("invalid range", procName, NULL);

    name = sarrayGetString(sa, first, L_NOCOPY);
    h = last - first;
    line = sarrayGetString(sa, first + 1, L_NOCOPY);
    len = strlen(line);
    if (line[0] != '"' || line[len - 1] != '"')
        return (SEL *)ERROR_PTR("invalid format", procName, NULL);
    w = len - 2;
    if ((sel = selCreate(h, w, name)) == NULL)
        return (SEL *)ERROR_PTR("sel not made", procName, NULL);
    for (i = first + 1; i <= last; i++) {
        line = sarrayGetString(sa, i, L_NOCOPY);
        y = i - first - 1;
        for (x = 0; x < w; ++x) {
            ch = line[x + 1];  /* skip the leading double-quote */
            switch (ch)
            {
                case 'X':
                    selSetOrigin(sel, y, x);  /* set origin and hit */
                case 'x':
                    selSetElement(sel, y, x, SEL_HIT);
                    break;

                case 'O':
                    selSetOrigin(sel, y, x);  /* set origin and miss */
                case 'o':
                    selSetElement(sel, y, x, SEL_MISS);
                    break;

                case 'C':
                    selSetOrigin(sel, y, x);  /* set origin and don't-care */
                case ' ':
                    selSetElement(sel, y, x, SEL_DONT_CARE);
                    break;

                default:
                    selDestroy(&sel);
                    return (SEL *)ERROR_PTR("unknown char", procName, NULL);
            }
        }
    }

    return sel;
}

Project: leptonica
File: sel1.c

selCreateFromString(const char  *text,
                    l_int32      h,
                    l_int32      w,
                    const char  *name)
{
SEL     *sel;
l_int32  y, x, norig;
char     ch;

    PROCNAME("selCreateFromString");

    if (h < 1)
        return (SEL *)ERROR_PTR("height must be > 0", procName, NULL);
    if (w < 1)
        return (SEL *)ERROR_PTR("width must be > 0", procName, NULL);

    sel = selCreate(h, w, name);

    norig = 0;
    for (y = 0; y < h; ++y) {
        for (x = 0; x < w; ++x) {
            ch = *(text++);
            switch (ch)
            {
                case 'X':
                    norig++;
                    selSetOrigin(sel, y, x);
                case 'x':
                    selSetElement(sel, y, x, SEL_HIT);
                    break;

                case 'O':
                    norig++;
                    selSetOrigin(sel, y, x);
                case 'o':
                    selSetElement(sel, y, x, SEL_MISS);
                    break;

                case 'C':
                    norig++;
                    selSetOrigin(sel, y, x);
                case ' ':
                    selSetElement(sel, y, x, SEL_DONT_CARE);
                    break;

                case '\n':
                    /* ignored */
                    continue;

                default:
                    selDestroy(&sel);
                    return (SEL *)ERROR_PTR("unknown char", procName, NULL);
            }
        }
    }
    if (norig != 1) {
        L_ERROR("Exactly one origin must be specified; this string has %d\n",
                procName, norig);
        selDestroy(&sel);
    }

    return sel;
}

Project: leptonica
File: sel1.c

selDestroy(SEL  **psel)
{
l_int32  i;
SEL     *sel;

    PROCNAME("selDestroy");

    if (psel == NULL)  {
        L_WARNING("ptr address is NULL!\n", procName);
        return;
    }
    if ((sel = *psel) == NULL)
        return;

    for (i = 0; i < sel->sy; i++)
        LEPT_FREE(sel->data[i]);
    LEPT_FREE(sel->data);
    if (sel->name)
        LEPT_FREE(sel->name);
    LEPT_FREE(sel);

    *psel = NULL;
    return;
}

Project: leptonica
File: sel1.c

selDisplayInPix(SEL     *sel,
                l_int32  size,
                l_int32  gthick)
{
l_int32  i, j, w, h, sx, sy, cx, cy, type, width;
l_int32  radius1, radius2, shift1, shift2, x0, y0;
PIX     *pixd, *pix2, *pixh, *pixm, *pixorig;
PTA     *pta1, *pta2, *pta1t, *pta2t;

    PROCNAME("selDisplayInPix");

    if (!sel)
        return (PIX *)ERROR_PTR("sel not defined", procName, NULL);
    if (size < 13) {
        L_WARNING("size < 13; setting to 13\n", procName);
        size = 13;
    }
    if (size % 2 == 0)
        size++;
    if (gthick < 2) {
        L_WARNING("grid thickness < 2; setting to 2\n", procName);
        gthick = 2;
    }
    selGetParameters(sel, &sy, &sx, &cy, &cx);
    w = size * sx + gthick * (sx + 1);
    h = size * sy + gthick * (sy + 1);
    pixd = pixCreate(w, h, 1);

        /* Generate grid lines */
    for (i = 0; i <= sy; i++)
        pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick),
                      w - 1, gthick / 2 + i * (size + gthick),
                      gthick, L_SET_PIXELS);
    for (j = 0; j <= sx; j++)
        pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0,
                      gthick / 2 + j * (size + gthick), h - 1,
                      gthick, L_SET_PIXELS);

        /* Generate hit and miss patterns */
    radius1 = (l_int32)(0.85 * ((size - 1) / 2.0) + 0.5);  /* of hit */
    radius2 = (l_int32)(0.65 * ((size - 1) / 2.0) + 0.5);  /* of inner miss */
    pta1 = generatePtaFilledCircle(radius1);
    pta2 = generatePtaFilledCircle(radius2);
    shift1 = (size - 1) / 2 - radius1;  /* center circle in square */
    shift2 = (size - 1) / 2 - radius2;
    pta1t = ptaTransform(pta1, shift1, shift1, 1.0, 1.0);
    pta2t = ptaTransform(pta2, shift2, shift2, 1.0, 1.0);
    pixh = pixGenerateFromPta(pta1t, size, size);  /* hits */
    pix2 = pixGenerateFromPta(pta2t, size, size);
    pixm = pixSubtract(NULL, pixh, pix2);

        /* Generate crossed lines for origin pattern */
    pixorig = pixCreate(size, size, 1);
    width = size / 8;
    pixRenderLine(pixorig, size / 2, (l_int32)(0.12 * size),
                           size / 2, (l_int32)(0.88 * size),
                           width, L_SET_PIXELS);
    pixRenderLine(pixorig, (l_int32)(0.15 * size), size / 2,
                           (l_int32)(0.85 * size), size / 2,
                           width, L_FLIP_PIXELS);
    pixRasterop(pixorig, size / 2 - width, size / 2 - width,
                2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0);

        /* Specialize origin pattern for this sel */
    selGetTypeAtOrigin(sel, &type);
    if (type == SEL_HIT)
        pixXor(pixorig, pixorig, pixh);
    else if (type == SEL_MISS)
        pixXor(pixorig, pixorig, pixm);

        /* Paste the patterns in */
    y0 = gthick;
    for (i = 0; i < sy; i++) {
        x0 = gthick;
        for (j = 0; j < sx; j++) {
            selGetElement(sel, i, j, &type);
            if (i == cy && j == cx)  /* origin */
                pixRasterop(pixd, x0, y0, size, size, PIX_SRC, pixorig, 0, 0);
            else if (type == SEL_HIT)
                pixRasterop(pixd, x0, y0, size, size, PIX_SRC, pixh, 0, 0);
            else if (type == SEL_MISS)
                pixRasterop(pixd, x0, y0, size, size, PIX_SRC, pixm, 0, 0);
            x0 += size + gthick;
        }
        y0 += size + gthick;
    }

    pixDestroy(&pix2);
    pixDestroy(&pixh);
    pixDestroy(&pixm);
    pixDestroy(&pixorig);
    ptaDestroy(&pta1);
    ptaDestroy(&pta1t);
    ptaDestroy(&pta2);
    ptaDestroy(&pta2t);
    return pixd;
}

Project: leptonica
File: sel1.c

selFindMaxTranslations(SEL      *sel,
                       l_int32  *pxp,
                       l_int32  *pyp,
                       l_int32  *pxn,
                       l_int32  *pyn)
{
l_int32  sx, sy, cx, cy, i, j;
l_int32  maxxp, maxyp, maxxn, maxyn;

    PROCNAME("selaFindMaxTranslations");

    if (!pxp || !pyp || !pxn || !pyn)
        return ERROR_INT("&xp (etc) defined", procName, 1);
    *pxp = *pyp = *pxn = *pyn = 0;
    if (!sel)
        return ERROR_INT("sel not defined", procName, 1);
    selGetParameters(sel, &sy, &sx, &cy, &cx);

    maxxp = maxyp = maxxn = maxyn = 0;
    for (i = 0; i < sy; i++) {
        for (j = 0; j < sx; j++) {
            if (sel->data[i][j] == 1) {
                maxxp = L_MAX(maxxp, cx - j);
                maxyp = L_MAX(maxyp, cy - i);
                maxxn = L_MAX(maxxn, j - cx);
                maxyn = L_MAX(maxyn, i - cy);
            }
        }
    }

    *pxp = maxxp;
    *pyp = maxyp;
    *pxn = maxxn;
    *pyn = maxyn;

    return 0;
}

Project: leptonica
File: sel1.c

selGetElement(SEL      *sel,
              l_int32   row,
              l_int32   col,
              l_int32  *ptype)
{
    PROCNAME("selGetElement");

    if (!ptype)
        return ERROR_INT("&type not defined", procName, 1);
    *ptype = SEL_DONT_CARE;
    if (!sel)
        return ERROR_INT("sel not defined", procName, 1);
    if (row < 0 || row >= sel->sy)
        return ERROR_INT("sel row out of bounds", procName, 1);
    if (col < 0 || col >= sel->sx)
        return ERROR_INT("sel col out of bounds", procName, 1);

    *ptype = sel->data[row][col];
    return 0;
}

Project: leptonica
File: sel1.c

selGetName(SEL  *sel)
{
    PROCNAME("selGetName");

    if (!sel)
        return (char *)ERROR_PTR("sel not defined", procName, NULL);

    return sel->name;
}

Project: leptonica
File: sel1.c

selGetTypeAtOrigin(SEL      *sel,
                   l_int32  *ptype)
{
l_int32  sx, sy, cx, cy, i, j;

    PROCNAME("selGetTypeAtOrigin");

    if (!ptype)
        return ERROR_INT("&type not defined", procName, 1);
    *ptype = SEL_DONT_CARE;  /* init */
    if (!sel)
        return ERROR_INT("sel not defined", procName, 1);

    selGetParameters(sel, &sy, &sx, &cy, &cx);
    for (i = 0; i < sy; i++) {
        for (j = 0; j < sx; j++) {
            if (i == cy && j == cx) {
                selGetElement(sel, i, j, ptype);
                return 0;
            }
        }
    }

    return ERROR_INT("sel origin not found", procName, 1);
}

Project: leptonica
File: sel1.c

selPrintToString(SEL  *sel)
{
char     is_center;
char    *str, *strptr;
l_int32  type;
l_int32  sx, sy, cx, cy, x, y;

    PROCNAME("selPrintToString");

    if (!sel)
        return (char *)ERROR_PTR("sel not defined", procName, NULL);

    selGetParameters(sel, &sy, &sx, &cy, &cx);
    if ((str = (char *)LEPT_CALLOC(1, sy * (sx + 1) + 1)) == NULL)
        return (char *)ERROR_PTR("calloc fail for str", procName, NULL);
    strptr = str;

    for (y = 0; y < sy; ++y) {
        for (x = 0; x < sx; ++x) {
            selGetElement(sel, y, x, &type);
            is_center = (x == cx && y == cy);
            switch (type) {
                case SEL_HIT:
                    *(strptr++) = is_center ? 'X' : 'x';
                    break;
                case SEL_MISS:
                    *(strptr++) = is_center ? 'O' : 'o';
                    break;
                case SEL_DONT_CARE:
                    *(strptr++) = is_center ? 'C' : ' ';
                    break;
            }
        }
        *(strptr++) = '\n';
    }

    return str;
}

Project: leptonica
File: sel1.c

selRead(const char  *fname)
{
FILE  *fp;
SEL   *sel;

    PROCNAME("selRead");

    if (!fname)
        return (SEL *)ERROR_PTR("fname not defined", procName, NULL);

    if ((fp = fopenReadStream(fname)) == NULL)
        return (SEL *)ERROR_PTR("stream not opened", procName, NULL);
    if ((sel = selReadStream(fp)) == NULL) {
        fclose(fp);
        return (SEL *)ERROR_PTR("sela not returned", procName, NULL);
    }
    fclose(fp);

    return sel;
}

Project: leptonica
File: sel1.c

selRotateOrth(SEL     *sel,
              l_int32  quads)
{
l_int32  i, j, ni, nj, sx, sy, cx, cy, nsx, nsy, ncx, ncy, type;
SEL     *seld;

    PROCNAME("selRotateOrth");

    if (!sel)
        return (SEL *)ERROR_PTR("sel not defined", procName, NULL);
    if (quads < 0 || quads > 4)
        return (SEL *)ERROR_PTR("quads not in {0,1,2,3,4}", procName, NULL);
    if (quads == 0 || quads == 4)
        return selCopy(sel);

    selGetParameters(sel, &sy, &sx, &cy, &cx);
    if (quads == 1) {  /* 90 degrees cw */
        nsx = sy;
        nsy = sx;
        ncx = sy - cy - 1;
        ncy = cx;
    } else if (quads == 2) {  /* 180 degrees cw */
        nsx = sx;
        nsy = sy;
        ncx = sx - cx - 1;
        ncy = sy - cy - 1;
    } else {  /* 270 degrees cw */
        nsx = sy;
        nsy = sx;
        ncx = cy;
        ncy = sx - cx - 1;
    }
    seld = selCreateBrick(nsy, nsx, ncy, ncx, SEL_DONT_CARE);
    if (sel->name)
        seld->name = stringNew(sel->name);

    for (i = 0; i < sy; i++) {
        for (j = 0; j < sx; j++) {
            selGetElement(sel, i, j, &type);
            if (quads == 1) {
               ni = j;
               nj = sy - i - 1;
            } else if (quads == 2) {
               ni = sy - i - 1;
               nj = sx - j - 1;
            } else {  /* quads == 3 */
               ni = sx - j - 1;
               nj = i;
            }
            selSetElement(seld, ni, nj, type);
        }
    }

    return seld;
}

Project: leptonica
File: sel1.c

selSetElement(SEL     *sel,
              l_int32  row,
              l_int32  col,
              l_int32  type)
{
    PROCNAME("selSetElement");

    if (!sel)
        return ERROR_INT("sel not defined", procName, 1);
    if (type != SEL_HIT && type != SEL_MISS && type != SEL_DONT_CARE)
        return ERROR_INT("invalid sel element type", procName, 1);
    if (row < 0 || row >= sel->sy)
        return ERROR_INT("sel row out of bounds", procName, 1);
    if (col < 0 || col >= sel->sx)
        return ERROR_INT("sel col out of bounds", procName, 1);

    sel->data[row][col] = type;
    return 0;
}

Project: leptonica
File: sel1.c

selSetOrigin(SEL     *sel,
             l_int32  cy,
             l_int32  cx)
{
    PROCNAME("selSetOrigin");

    if (!sel)
        return ERROR_INT("sel not defined", procName, 1);
    sel->cy = cy;
    sel->cx = cx;
    return 0;
}

Project: leptonica
File: sel1.c

selaAddSel(SELA        *sela,
           SEL         *sel,
           const char  *selname,
           l_int32      copyflag)
{
l_int32  n;
SEL     *csel;

    PROCNAME("selaAddSel");

    if (!sela)
        return ERROR_INT("sela not defined", procName, 1);
    if (!sel)
        return ERROR_INT("sel not defined", procName, 1);
    if (!sel->name && !selname)
        return ERROR_INT("added sel must have name", procName, 1);
    if (copyflag != L_INSERT && copyflag != L_COPY)
        return ERROR_INT("invalid copyflag", procName, 1);

    if (copyflag == L_COPY) {
        if ((csel = selCopy(sel)) == NULL)
            return ERROR_INT("csel not made", procName, 1);
    } else {  /* copyflag == L_INSERT */
        csel = sel;
    }
    if (!csel->name)
        csel->name = stringNew(selname);

    n = selaGetCount(sela);
    if (n >= sela->nalloc)
        selaExtendArray(sela);
    sela->sel[n] = csel;
    sela->n++;

    return 0;
}

Project: leptonica
File: sel1.c

selaCreate(l_int32  n)
{
SELA  *sela;

    PROCNAME("selaCreate");

    if (n <= 0)
        n = INITIAL_PTR_ARRAYSIZE;
    if (n > MANY_SELS)
        L_WARNING("%d sels\n", procName, n);

    if ((sela = (SELA *)LEPT_CALLOC(1, sizeof(SELA))) == NULL)
        return (SELA *)ERROR_PTR("sela not made", procName, NULL);

    sela->nalloc = n;
    sela->n = 0;

        /* make array of se ptrs */
    if ((sela->sel = (SEL **)LEPT_CALLOC(n, sizeof(SEL *))) == NULL) {
        LEPT_FREE(sela);
        return (SELA *)ERROR_PTR("sel ptrs not made", procName, NULL);
    }
    return sela;
}

Project: leptonica
File: sel1.c

selaCreateFromFile(const char  *filename)
{
char    *filestr, *line;
l_int32  i, n, first, last, nsel, insel;
size_t   nbytes;
NUMA    *nafirst, *nalast;
SARRAY  *sa;
SEL     *sel;
SELA    *sela;

    PROCNAME("selaCreateFromFile");

    if (!filename)
        return (SELA *)ERROR_PTR("filename not defined", procName, NULL);

    filestr = (char *)l_binaryRead(filename, &nbytes);
    sa = sarrayCreateLinesFromString(filestr, 1);
    LEPT_FREE(filestr);
    n = sarrayGetCount(sa);
    sela = selaCreate(0);

        /* Find the start and end lines for each Sel.
         * We allow the "blank" lines to be null strings or
         * to have standard whitespace (' ','\t',\'n') or be '#'. */
    nafirst = numaCreate(0);
    nalast = numaCreate(0);
    insel = FALSE;
    for (i = 0; i < n; i++) {
        line = sarrayGetString(sa, i, L_NOCOPY);
        if (!insel &&
            (line[0] != '\0' && line[0] != ' ' &&
             line[0] != '\t' && line[0] != '\n' && line[0] != '#')) {
            numaAddNumber(nafirst, i);
            insel = TRUE;
            continue;
        }
        if (insel &&
            (line[0] == '\0' || line[0] == ' ' ||
             line[0] == '\t' || line[0] == '\n' || line[0] == '#')) {
            numaAddNumber(nalast, i - 1);
            insel = FALSE;
            continue;
        }
    }
    if (insel)  /* fell off the end of the file */
        numaAddNumber(nalast, n - 1);

        /* Extract sels */
    nsel = numaGetCount(nafirst);
    for (i = 0; i < nsel; i++) {
        numaGetIValue(nafirst, i, &first);
        numaGetIValue(nalast, i, &last);
        if ((sel = selCreateFromSArray(sa, first, last)) == NULL) {
            fprintf(stderr, "Error reading sel from %d to %d\n", first, last);
            selaDestroy(&sela);
            sarrayDestroy(&sa);
            numaDestroy(&nafirst);
            numaDestroy(&nalast);
            return (SELA *)ERROR_PTR("bad sela file", procName, NULL);
        }
        selaAddSel(sela, sel, NULL, 0);
    }

    numaDestroy(&nafirst);
    numaDestroy(&nalast);
    sarrayDestroy(&sa);
    return sela;
}

Project: leptonica
File: sel1.c

selaDestroy(SELA  **psela)
{
SELA    *sela;
l_int32  i;

    if (!psela) return;
    if ((sela = *psela) == NULL)
        return;

    for (i = 0; i < sela->n; i++)
        selDestroy(&sela->sel[i]);
    LEPT_FREE(sela->sel);
    LEPT_FREE(sela);
    *psela = NULL;
    return;
}

Project: leptonica
File: sel1.c

selaDisplayInPix(SELA    *sela,
                 l_int32  size,
                 l_int32  gthick,
                 l_int32  spacing,
                 l_int32  ncols)
{
l_int32  nsels, i, w, width;
PIX     *pixt, *pixd;
PIXA    *pixa;
SEL     *sel;

    PROCNAME("selaDisplayInPix");

    if (!sela)
        return (PIX *)ERROR_PTR("sela not defined", procName, NULL);
    if (size < 13) {
        L_WARNING("size < 13; setting to 13\n", procName);
        size = 13;
    }
    if (size % 2 == 0)
        size++;
    if (gthick < 2) {
        L_WARNING("grid thickness < 2; setting to 2\n", procName);
        gthick = 2;
    }
    if (spacing < 5) {
        L_WARNING("spacing < 5; setting to 5\n", procName);
        spacing = 5;
    }

        /* Accumulate the pix of each sel */
    nsels = selaGetCount(sela);
    pixa = pixaCreate(nsels);
    for (i = 0; i < nsels; i++) {
        sel = selaGetSel(sela, i);
        pixt = selDisplayInPix(sel, size, gthick);
        pixaAddPix(pixa, pixt, L_INSERT);
    }

        /* Find the tiled output width, using just the first
         * ncols pix in the pixa.   If all pix have the same width,
         * they will align properly in columns. */
    width = 0;
    ncols = L_MIN(nsels, ncols);
    for (i = 0; i < ncols; i++) {
        pixt = pixaGetPix(pixa, i, L_CLONE);
        pixGetDimensions(pixt, &w, NULL, NULL);
        width += w;
        pixDestroy(&pixt);
    }
    width += (ncols + 1) * spacing;  /* add spacing all around as well */

    pixd = pixaDisplayTiledInRows(pixa, 1, width, 1.0, 0, spacing, 0);
    pixaDestroy(&pixa);
    return pixd;
}

Project: leptonica
File: sel1.c

selaExtendArray(SELA  *sela)
{
    PROCNAME("selaExtendArray");

    if (!sela)
        return ERROR_INT("sela not defined", procName, 1);

    if ((sela->sel = (SEL **)reallocNew((void **)&sela->sel,
                              sizeof(SEL *) * sela->nalloc,
                              2 * sizeof(SEL *) * sela->nalloc)) == NULL)
            return ERROR_INT("new ptr array not returned", procName, 1);

    sela->nalloc = 2 * sela->nalloc;
    return 0;
}

Project: leptonica
File: sel1.c

selaFindSelByName(SELA        *sela,
                  const char  *name,
                  l_int32     *pindex,
                  SEL        **psel)
{
l_int32  i, n;
char    *sname;
SEL     *sel;

    PROCNAME("selaFindSelByName");

    if (pindex) *pindex = -1;
    if (psel) *psel = NULL;

    if (!sela)
        return ERROR_INT("sela not defined", procName, 1);

    n = selaGetCount(sela);
    for (i = 0; i < n; i++)
    {
        if ((sel = selaGetSel(sela, i)) == NULL) {
            L_WARNING("missing sel\n", procName);
            continue;
        }

        sname = selGetName(sel);
        if (sname && (!strcmp(name, sname))) {
            if (pindex)
                *pindex = i;
            if (psel)
                *psel = sel;
            return 0;
        }
    }

    return 1;
}

Project: leptonica
File: sel1.c

selaGetBrickName(SELA    *sela,
                 l_int32  hsize,
                 l_int32  vsize)
{
l_int32  i, nsels, sx, sy;
SEL     *sel;

    PROCNAME("selaGetBrickName");

    if (!sela)
        return (char *)ERROR_PTR("sela not defined", procName, NULL);

    nsels = selaGetCount(sela);
    for (i = 0; i < nsels; i++) {
        sel = selaGetSel(sela, i);
        selGetParameters(sel, &sy, &sx, NULL, NULL);
        if (hsize == sx && vsize == sy)
            return stringNew(selGetName(sel));
    }

    return (char *)ERROR_PTR("sel not found", procName, NULL);
}

Project: leptonica
File: sel1.c

selaGetCount(SELA  *sela)
{
    PROCNAME("selaGetCount");

    if (!sela)
        return ERROR_INT("sela not defined", procName, 0);

    return sela->n;
}

Project: leptonica
File: sel1.c

selaGetSel(SELA    *sela,
           l_int32  i)
{
    PROCNAME("selaGetSel");

    if (!sela)
        return (SEL *)ERROR_PTR("sela not defined", procName, NULL);

    if (i < 0 || i >= sela->n)
        return (SEL *)ERROR_PTR("invalid index", procName, NULL);
    return sela->sel[i];
}

Project: leptonica
File: sel1.c

selaRead(const char  *fname)
{
FILE  *fp;
SELA  *sela;

    PROCNAME("selaRead");

    if (!fname)
        return (SELA *)ERROR_PTR("fname not defined", procName, NULL);

    if ((fp = fopenReadStream(fname)) == NULL)
        return (SELA *)ERROR_PTR("stream not opened", procName, NULL);
    if ((sela = selaReadStream(fp)) == NULL) {
        fclose(fp);
        return (SELA *)ERROR_PTR("sela not returned", procName, NULL);
    }
    fclose(fp);

    return sela;
}

Project: leptonica
File: sel1.c

selaReadStream(FILE  *fp)
{
l_int32  i, n, version;
SEL     *sel;
SELA    *sela;

    PROCNAME("selaReadStream");

    if (!fp)
        return (SELA *)ERROR_PTR("stream not defined", procName, NULL);

    if (fscanf(fp, "\nSela Version %d\n", &version) != 1)
        return (SELA *)ERROR_PTR("not a sela file", procName, NULL);
    if (version != SEL_VERSION_NUMBER)
        return (SELA *)ERROR_PTR("invalid sel version", procName, NULL);
    if (fscanf(fp, "Number of Sels = %d\n\n", &n) != 1)
        return (SELA *)ERROR_PTR("not a sela file", procName, NULL);

    if ((sela = selaCreate(n)) == NULL)
        return (SELA *)ERROR_PTR("sela not made", procName, NULL);
    sela->nalloc = n;

    for (i = 0; i < n; i++) {
        if ((sel = selReadStream(fp)) == NULL) {
            selaDestroy(&sela);
            return (SELA *)ERROR_PTR("sel not read", procName, NULL);
        }
        selaAddSel(sela, sel, NULL, 0);
    }

    return sela;
}

Project: leptonica
File: sel1.c

selaWrite(const char  *fname,
          SELA        *sela)
{
FILE  *fp;

    PROCNAME("selaWrite");

    if (!fname)
        return ERROR_INT("fname not defined", procName, 1);
    if (!sela)
        return ERROR_INT("sela not defined", procName, 1);

    if ((fp = fopenWriteStream(fname, "wb")) == NULL)
        return ERROR_INT("stream not opened", procName, 1);
    selaWriteStream(fp, sela);
    fclose(fp);

    return 0;
}

Project: leptonica
File: sel1.c

selaWriteStream(FILE  *fp,
                SELA  *sela)
{
l_int32  i, n;
SEL     *sel;

    PROCNAME("selaWriteStream");

    if (!fp)
        return ERROR_INT("stream not defined", procName, 1);
    if (!sela)
        return ERROR_INT("sela not defined", procName, 1);

    n = selaGetCount(sela);
    fprintf(fp, "\nSela Version %d\n", SEL_VERSION_NUMBER);
    fprintf(fp, "Number of Sels = %d\n\n", n);
    for (i = 0; i < n; i++) {
        if ((sel = selaGetSel(sela, i)) == NULL)
            continue;
        selWriteStream(fp, sel);
    }
    return 0;
}