#help_index "File/Internal"
I64 DirTreeSerializeSize(CDirEntry *tmpde)
{
        I64 res = 0;

        while (tmpde)
        {
                res += CDIR_SIZE + 1;
                if (tmpde->attr & RS_ATTR_DIR)
                        res += DirTreeSerializeSize(tmpde->sub);
                tmpde = tmpde->next;
        }

        return res + 1;
}
I64 DirTreeSerializeFill(CDirEntry *tmpde, U8 *dst)
{
        I64 res = 0, i;

        while (tmpde)
        {
                *dst++ = 1;
                res++;
                MemCopy(dst, &tmpde->start, CDIR_SIZE);
                dst += CDIR_SIZE;
                res += CDIR_SIZE;
                if (tmpde->attr & RS_ATTR_DIR)
                {
                        i = DirTreeSerializeFill(tmpde->sub, dst);
                        dst += i;
                        res += i;
                }
                tmpde = tmpde->next;
        }
        *dst = 0;

        return res + 1;
}
public U8 *DirTreeSerialize(CDirEntry *tmpde, I64 *_size=NULL)
{//Serialize tree returned from FilesFind() into a one contiguous U8 array.
        I64 size = DirTreeSerializeSize(tmpde);
        U8 *buf = MAlloc(size);

        DirTreeSerializeFill(tmpde, buf);
        if (_size)
                *_size = size;

        return buf;
}

U8 *DirTreeUnserialize2(U8 *src, CDirEntry **tmpde)
{
        CDirEntry *tmpde1;

        if (*src++)
        {
                tmpde1 = CAlloc(sizeof(CDirEntry));
                *tmpde = tmpde1;
                MemCopy(&tmpde1->start, src, CDIR_SIZE);
                src += CDIR_SIZE;
                if (tmpde1->attr & RS_ATTR_DIR)
                        src = DirTreeUnserialize2(src, &tmpde1->sub);
                src = DirTreeUnserialize2(src, &tmpde1->next);
        }
        else
                *tmpde = NULL;

        return src;
}
public CDirEntry *DirTreeUnserialize(U8 *src)
{//Unserialize tree to make it like a tree returned from FilesFind().
        CDirEntry *tmpde = NULL;

        DirTreeUnserialize2(src, &tmpde);

        return tmpde;
}

#help_index "File/Program Routines"
U0 FOFlatten(CDirEntry *tmpde, CDirEntry **a, I64 *i)
{
        CDirEntry *tmpde1;

        while (tmpde)
        {
                tmpde1 = tmpde->next;
                if (tmpde->attr & RS_ATTR_DIR)
                {
                        FOFlatten(tmpde->sub, a, i);
                        DirEntryDel(tmpde);
                }
                else
                {
                        a[*i] = tmpde;
                        *i = *i + 1;
                }
                tmpde = tmpde1;
        }
}

I64 Size1(CDirEntry *tmpde,I64 round_to)
{
        I64 res = 0, i;

        while (tmpde)
        {
                i = tmpde->size;

                if (round_to)
                        i = CeilU64(tmpde->size, round_to);
                if (tmpde->attr & RS_ATTR_DIR)
                        i += Size1(tmpde->sub, round_to);
                tmpde->user_data = i; //Store size in user_data member
                res += i;
                tmpde = tmpde->next;
        }

        return res;
}
public I64 Size(U8 *files_find_mask="/*", U8 *fu_flags=NULL, I64 round_to=0)
{//Total size of files in mask.
//Does not include directory size of base directory, but does include size of sub directories.
        I64                      fuf_flags = 0, res = 0;
        CDirEntry       *tmpde1 = NULL;

        FlagsScan(&fuf_flags, Define("ST_FILE_UTIL_FLAGS"), "+r");
        FlagsScan(&fuf_flags, Define("ST_FILE_UTIL_FLAGS"), fu_flags);
        if (tmpde1 = FilesFind(files_find_mask, fuf_flags & FUG_FILES_FIND))
        {
                res = Size1(tmpde1, round_to);
                DirTreeDel(tmpde1);
        }

        return res;
}

public I64 FileCount(CDirEntry *tmpde)
{//Count of files in CDirEntry tree.
        I64 count = 0;

        while (tmpde)
        {
                if (tmpde->attr & RS_ATTR_DIR)
                        count += FileCount(tmpde->sub);
                else
                        count++;
                tmpde = tmpde->next;
        }

        return count;
}

#help_index "File/Cmd Line (Typically);Cmd Line (Typically)"
public I64 FF(U8 *files_find_mask, U8 *fu_flags=NULL)
{//Files find. List files matching mask.
        I64                      count = 0, fuf_flags = 0;
        CDirEntry       *tmpde, *tmpde1;

        FlagsScan(&fuf_flags, Define("ST_FILE_UTIL_FLAGS"), "+r+f+F");
        FlagsScan(&fuf_flags, Define("ST_FILE_UTIL_FLAGS"), fu_flags);
        tmpde = tmpde1 = FilesFind(files_find_mask, fuf_flags);
        while (tmpde)
        {
                PutFileLink(tmpde->full_name);
                '\n';
                count++;
                tmpde = tmpde->next;
        }
        DirTreeDel(tmpde1);

        return count;
}