slicid
slicid

Reputation: 9

Add 4 bytes every 1 byte to file buffer

I'd like to add 1 byte every 4 bytes as it reads the file to the buffer. Once I use my code it adds the bytes to the end of the file instead of every 4 bytes. I'm having trouble and now I'd like some help so I'm here. Thanks for taking interest in reading my post.

Here's my code:

BYTE* ReadFileToMem(WCHAR* szFileName, DWORD& dwSize)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return 0;

    dwSize = GetFileSize(hFile, NULL);

    if (!dwSize)
        return 0;

    BYTE* pFileBuffer = (BYTE*)VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!pFileBuffer)
        return 0;

    DWORD dwRead = 0;
    ReadFile(hFile, pFileBuffer, dwSize, &dwRead, NULL);
    CloseHandle(hFile);


    int allocSize{};
    for (int i = 0; i < dwSize; i++)
    {
        if (i % 4) continue;
        allocSize++;
    }

    int afterSize = allocSize + dwSize;

    BYTE* pFileBufferB = (BYTE*)VirtualAlloc(NULL, afterSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    LPBYTE p = pFileBuffer;
    for (int i = 0; i < dwSize; i++)
    {
        if (i % 4) continue;
        *pFileBufferB = *p;
        pFileBufferB++;
        p++;
    }

    cout << allocSize;

    return pFileBufferB;
}

Upvotes: 0

Views: 445

Answers (3)

Loki Astari
Loki Astari

Reputation: 264689

This is the perfect situation for modifying the local object on the stream to modify the input stream.

What you want to do is create std::codecvt facet and add it to a local and imbue the filestream with this local. After you have done this the stream will automatically add the space every forth element and your code that uses the stream will not need to d anything.

#include <locale>
#include <fstream>
#include <iostream>

// 
class AddSpaceEveryFourthCharacter: public std::codecvt<char,char,mbstate_t>
{
    public:
        using MyType        = std::codecvt<char,char,mbstate_t>;
        using state_type    = MyType::state_type;
        using intern_type   = MyType::intern_type;
        using extern_type   = MyType::extern_type;
        using result        = MyType::result;

        // This indicates that we are converting the input.
        // Thus forcing a call to do_in()
        virtual bool do_always_noconv() const throw()   {return false;}

        // As the buffer is read we read data from "from" and place it
        // into "to". As long as we have at least 4 characters in "from"
        // and at least 5 characters on the "to" we can copy data (and add
        // the extra byte).
        virtual result do_in(state_type& state,
                const extern_type* from, const extern_type* from_end, const extern_type*& from_next,
                intern_type*       to,   intern_type*       to_end,   intern_type*&       to_next
        ) const
        {
            std::size_t fromLen = from_end - from;
            std::size_t toLen   = to_end - to;
            // extract the state of any partial conversions (see below)
            int leftOver = *reinterpret_cast<char*>(&state);

            while(fromLen >= 4 && toLen >= 5) {
                for(int loop = leftOver; loop < 4; ++loop) {
                    *to++ = *from++;
                }
                *to++ = '-';  // You did not specify what the extra byte
                              // was so I guessed at a 'dash'.
                fromLen -= 4;
                toLen   -= 5;
                leftOver = 0;
            }

            // Copy any remaining characters that will fit from "from"
            while(fromLen > 0 && toLen > 0) {
                *to++ = *from++;
                --fromLen;
                --toLen;
                ++leftOver;
            }

            // Keep track of any partial conversions.
            (*reinterpret_cast<char*>(&state))    = static_cast<char>(leftOver);

            // When we have converted as much as possible update the
            // output parameters to show where you got to.
            from_next = from;
            to_next   = to;

            // return the appropriate values.
            return (fromLen == 0) ? ok : partial;
        }
};

int main()
{
    // construct a custom filter locale and add it to a local.
    const std::locale filterLocale(std::cout.getloc(), new AddSpaceEveryFourthCharacter());

    // Create a file, imbue a local and then open the file.
    std::ifstream   file;
    file.imbue(filterLocale);
    file.open("test.data");

    // Now simply use the file as you would normally.
    std::string line;
    while (std::getline(file, line)) {
        std::cout << line << "\n";
    }
}

When I run this I get:

> cat test.data
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type specimen book.


> ./a.out
Lore-m Ip-sum -is s-impl-y du-mmy -text- of -the -prin-ting- and- typ-eset-ting- ind-ustr-y.
L-orem- Ips-um h-as b-een -the -indu-stry-'s s-tand-ard -dumm-y te-xt e-ver -sinc-e th-e 15-00s,-
whe-n an- unk-nown- pri-nter- too-k a -gall-ey o-f ty-pe a-nd s-cram-bled- it -to m-ake -a ty-pe s-peci-men -book-.

Upvotes: 1

RbMm
RbMm

Reputation: 33794

you need just allocate buffer ((file_size + 3) >> 2 ) * 5 for hold result. and then move data in it from the end to begin - in this case we can do all in single buffer without additional allocation

void ModifyBuffer(PULONG puFrom, ULONG NumberOfBytes /* != 0*/, UCHAR ExtraByte = 0)
{
    NumberOfBytes = (NumberOfBytes + 3) >> 2;

    union {
        PBYTE pbTo;
        PULONG puTo;
    };

    puFrom += NumberOfBytes, pbTo = (PBYTE)puFrom + NumberOfBytes;

    do 
    {
        *--pbTo = ExtraByte;
        *--puTo = *--puFrom;
    } while (--NumberOfBytes);
}

and all code:

inline ULONG BOOL_TO_ERROR(BOOL f)
{
    return f ? NOERROR : GetLastError();
}

ULONG ReadFileToMem(PCWSTR szFileName)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    FILE_STANDARD_INFO fsi;

    ULONG dwError = BOOL_TO_ERROR(GetFileInformationByHandleEx(hFile, FileStandardInfo, &fsi, sizeof(fsi)));

    if (dwError == NOERROR)
    {
        ULONG64 dwRequiredSize = ((fsi.EndOfFile.QuadPart + 3) >> 2 ) * 5;

        if (!fsi.EndOfFile.QuadPart)
        {
            dwError = ERROR_BUFFER_ALL_ZEROS;
        }
        else if (dwRequiredSize > MAXULONG)
        {
            dwError = ERROR_FILE_TOO_LARGE;
        }
        else
        {
            if (PVOID buf = LocalAlloc(0, (size_t)dwRequiredSize))
            {
                ULONG NumberOfBytes;

                dwError = BOOL_TO_ERROR(ReadFile(hFile, buf, fsi.EndOfFile.LowPart, &NumberOfBytes, 0));

                if (NOERROR == dwError)
                {
                    if (NumberOfBytes)
                    {
                        ModifyBuffer((PULONG)buf, NumberOfBytes);
                    }
                    else
                    {
                        dwError = ERROR_BUFFER_ALL_ZEROS;
                    }
                }

                LocalFree(buf);
            }
            else
            {
                dwError = GetLastError();
            }
        }
    }

    CloseHandle(hFile);

    return dwError;
}

Upvotes: 0

Drake Wu
Drake Wu

Reputation: 7190

Make sure to put the increment the pointer into the loop, You also need to avoid memory leaks:

#include <windows.h>
#include <iostream>
BYTE* ReadFileToMem(WCHAR* szFileName, DWORD& dwSize,DWORD& ByteSize)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return 0;

    dwSize = GetFileSize(hFile, NULL);

    if (!dwSize)
        return 0;

    BYTE* pFileBuffer = (BYTE*)VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!pFileBuffer)
        return 0;

    DWORD dwRead = 0;
    ReadFile(hFile, pFileBuffer, dwSize, &dwRead, NULL);
    CloseHandle(hFile);


    int allocSize{};
    for (int i = 1; i <= dwSize; i++)
    {
        if (i % 4) continue;
        allocSize++;
    }

    ByteSize = allocSize + dwSize;

    BYTE* pFileBufferB = (BYTE*)VirtualAlloc(NULL, ByteSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    BYTE* pp = pFileBufferB;
    LPBYTE p = pFileBuffer;
    for (int i = 1; i <= dwSize; i++, p++, pp++)
    {
        *pp = *p;
        if (i % 4 == 0)
        {
            pp++;
            *pp = '*';
        }

    }

    std::cout << allocSize;
    VirtualFree(pFileBuffer, dwSize, MEM_RELEASE);
    return pFileBufferB;
}
int main()
{
    DWORD dwSize = 0;
    DWORD ByteSize = 0;
    WCHAR file[] = L"test.txt";
    BYTE* pFileBufferB = ReadFileToMem(file, dwSize, ByteSize);
    //To Do;
    VirtualFree(pFileBufferB, ByteSize, MEM_RELEASE);
    return 0;
}

Or use std::string::insert(index,std::string):

#include <windows.h>
#include <iostream>
#include <vector>
#include <string>
std::string ReadFileToMem(WCHAR* szFileName, DWORD& dwSize)
{
    HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return 0;

    dwSize = GetFileSize(hFile, NULL);

    if (!dwSize)
        return 0;

    CHAR* pFileBuffer = (CHAR*)VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (!pFileBuffer)
        return 0;

    DWORD dwRead = 0;
    ReadFile(hFile, pFileBuffer, dwSize, &dwRead, NULL);
    CloseHandle(hFile);
    std::string tmp = pFileBuffer;
    VirtualFree(pFileBuffer, dwSize, MEM_RELEASE);
    for (int i = dwSize; i > 0; i--)
    {
        if (i % 4) continue;
        tmp.insert(i,"*");
    }

    return tmp;
}
int main()
{
    DWORD dwSize = 0;
    DWORD ByteSize = 0;
    WCHAR file[] = L"test.txt";
    std::string pFileBufferB = ReadFileToMem(file, dwSize, ByteSize);
    std::cout << pFileBufferB;
    return 0;
}

Upvotes: 0

Related Questions