c++ – Compare folders and find common files

I found this Powershell command useful in comparing folders and find common and different files.
Since I really like C and C++, I’ve decided to create a program to do that.

It will get all files in 2 folders given as arguments, will store them in an std::map,is that the correct container?
After, it will compare the 2 maps and give the common files.

Some notes:

The findFiles method should benefit from RAII treatment, but since I have ZERO work or internship experience, I am unable to implement that.

Some functions like finding a file size and iterating over a folder are present in C++ 17, but I use Digital Mars, an old compiler not up to date.

I use this compiler because it is small, provided as a compressed folder aka portable in the mainstream lexicon (even though portable means something else) and its use is straightforward.

I used an online code beautifier for indentation.

The sanitizePath method is used to eliminate trailing “/” or “” from the given path.

Please give all your valuable comments on this work.

#include <iostream>
#include <iterator>
#include <map>
#include <string>
#include <sys/stat.h>
#include <windows.h>

#ifndef INVALID_FILE_ATTRIBUTES
constexpr DWORD INVALID_FILE_ATTRIBUTES = ((DWORD)-1);
#endif

bool IsDir(const std::string &path)
{
    DWORD Attr;

    Attr = GetFileAttributes(path.c_str());
    if (Attr == INVALID_FILE_ATTRIBUTES)
    return false;

    return (bool)(Attr & FILE_ATTRIBUTE_DIRECTORY);
}

std::string sanitizePath(std::string const &input)
{
auto pos = input.find_last_not_of("/\");
return input.substr(0, pos + 1);
}

std::map<std::string, unsigned long > findFiles(std::string &spath)
{
size_t i = 1;
WIN32_FIND_DATA FindFileData;

std::map<std::string, unsigned long > list;

std::string sourcepath = spath + std::string("\*.*");

HANDLE hFind = FindFirstFile(sourcepath.c_str(), &FindFileData);

if (hFind != INVALID_HANDLE_VALUE)
    do {
        std::string fullpath = std::string(spath) + std::string("\") + std::string(FindFileData.cFileName);

        if (*(fullpath.rbegin()) == '.')
            continue;
        else
        if (FindFileData.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
            findFiles(fullpath);
        else
        {
            list(FindFileData.cFileName) = FindFileData.nFileSizeHigh *(MAXWORD + 1) + FindFileData.nFileSizeLow;
        }
    } while (FindNextFile(hFind, &FindFileData));

FindClose(hFind);

return list;
}

void displayMap(std::map<std::string, unsigned long > &map)
{
std::map<std::string, unsigned long>::const_iterator itr;

for (itr = map.begin(); itr != map.end(); itr++)
    std::cout << "File Name: " << itr->first << " Size: " << itr->second << " bytes" << std::endl;
}

std::map<std::string, unsigned long > map_intersect(std::map<std::string, unsigned long > const 
 &source, std::map<std::string, unsigned long > const &dest)
{
    std::map<std::string, unsigned long > inter;
    std::map<std::string, unsigned long>::const_iterator iter = dest.begin();
    std::map<std::string, unsigned long>::const_iterator end = dest.end();
    for (; iter != end; iter++)
    {
        if (source.find(iter->first) != source.end())
        {
        inter(iter->first) = iter->second;
        }
    }

    return inter;
   }

std::map<std::string, unsigned long > map_difference(std::map<std::string, unsigned long > const 
    &source, std::map<std::string, unsigned long > const &dest)
    {
        std::map<std::string, unsigned long > diff = source;
        std::map<std::string, unsigned long>::const_iterator iter = dest.begin();
        std::map<std::string, unsigned long>::const_iterator end = dest.end();
        for (; iter != end; iter++)
        {
            if (source.find(iter->first) != source.end())
            {
            diff.erase(iter->first);
            }
        }

        return diff;
    }

int main(int argc, char **argv)
{
if (argc <= 2)
{
    std::cerr << "No path or filename provided" << std::endl;
    return EXIT_FAILURE;
}

const char *source = argv(1);
const char *destination = argv(2);

if (!IsDir(source))
{
    std::cerr << "Source path doesn't exist" << std::endl;
    return EXIT_FAILURE;
}

if (!IsDir(destination))
{
    std::cerr << "Destination path doesn't exist" << std::endl;
    return EXIT_FAILURE;
}

std::string spath = sanitizePath(source);
std::string dpath = sanitizePath(destination);

std::cout << "Comparing " << spath << " and " << dpath << std::endl;

std::map<std::string, unsigned long > slist, dlist, ilist, diflist;

slist = findFiles(spath);
dlist = findFiles(dpath);

ilist = map_intersect(slist, dlist);
diflist = map_difference(slist, dlist);

if (ilist.empty())
    std::cout << "There is no common files" << std::endl;
else
{
    std::cout << "The common files are" << std::endl;
    displayMap(ilist);
}

if (diflist.empty())
    std::cout << "The 2 folder are the same" << std::endl;

return EXIT_SUCCESS;
}

code quality – Is it common to have to iterate on a design due to overlooking problems with it?

Iterating a through multiple versions of a design is a great thing to do! It is rare to create a design that has all the good properties at the first try. As software engineers, we should be humble and accept that we will make mistakes or overlook things. It is arrogant to think that you can create good design at your first try.

But as you say, it can be exhausting to work on same piece of code for prolonged period of time. But there might be practices and disciplines that make it more bearable.

Test automation, preferably TDD

This this the one discipline that enables us to actually change the design. By having solid and reliable suite of automated tests, the design can be changed drastically without fear of breaking existing functionality. It is that fear which is most exhausting.

Doing TDD also makes it more likely that you create working and ‘good enough’ design at your first try. This design then requires only small improvements to push it into greatness.

Refactoring

Instead of focusing on changing the whole design, focus on small problems and fix those. Fixing many small problems, will result in big changes in overall design. Making small changes is less mentally exhausting as you get feedback about your design sooner and you can stagger your attention between multiple designs, slowly improving all of them.

Good vs. Perfect

The saying ‘Perfect is the enemy of good.’ comes to mind here. Knowing when to stop trying to improve the design is learned skills. If the design is being used and changed, then you will have lots of small oportunities to improve the design, so you don’t have to invest all that time in the beginning. As long as you follow Boy Scouts rule of ‘Always leave code cleaner than you found it.’, then the design will improve over time.

object oriented – What does “common interface” mean in OOP?

I have seen the term “common interface” used a lot while reading books about OOP.

For example, the book The Essence of Object-Oriented Programming with Java and UML says the following:

Abstract classes usually define a common interface for subclasses by
specifying methods that all subclasses must override and define


My understanding of the term “common interface” is the following:

Assume that we have a superclass (or an interface or an abstract class) called Animal and two subclasses called Dog and Cat, and Animal have two virtual methods called makeSound() and move().

Now the common interface would be composed of two methods which are Animal.makeSound() and Animal.move().

Assume that we have the following code:

Animal animal1 = new Dog();
animal1.makeSound();
animal1.move();

animal1 = new Cat();
animal1.makeSound();
animal1.move();

The explanation of the above code is the following:

Animal animal1 = new Dog() creates an Animal common interface and associate a Dog object with it:

enter image description here

animal1.makeSound() sends an Animal.makeSound() message to the common interface, and then the common interface sends a Dog.makeSound() message to the Dog object:

enter image description here

Same thing happens in the case of animal1.move() (which is the Animal.move() message is sent to the common interface, etc.).

animal1 = new Cat() removes the Dog object from the common interface, and associate a Cat object with the common interface:

enter image description here

animal1.makeSound() sends an Animal.makeSound() message to the common interface, and then the common interface sends a Cat.makeSound() message to the Cat object:

enter image description here

Same thing happens in the case of animal1.move() (which is the Animal.move() message is sent to the common interface, etc.).

Am I correct in my understanding?

authentication – Client certificate common name? Subject alternative name?

For an IoT project, I want to secure client server communication. I want both the server (Apache) and the clients identify/authenticate each other (a client won’t communicate with other clients) before clients can post some data.

There is much less information about client certificates. Besides documentations, there are best practices. I would like to know, how to set common name and subject alternative names for clients, as they won’t have a domain name and a fix IP address.

Do I simply tell the server to ignore a mismatch? Can I use a wild card only CN (CN=*)? I also would like the cert to identify specific client. Server needs to be able to tell apart client 1 from client 2, etc…

Thanks!

sony alpha – Tethering DSLR camera to PC via any common WiFi network

I am aware that it is possible to tether a camera to PC via the WiFi network that is created by the WiFi-enabled camera itself. But I want to know if it is possible to tether by connecting both camera and PC to any other common WiFi network.

Specifically, I am using Sony Alpha6400 and qDSLRDashboard as PC client for tethering. I connected the camera to my home WiFi network (to which my PC is connected). But I do not know how to go ahead. qDSLRDashboard does not seem to recognize the camera connected to same WiFi network.

Note: I have not tried this in Sony Imaging Edge. This question is specific to qDSLRDashboard.

Thank you for your answers.

tripod heads – Which are the most common quick release plate systems out there

The camera has a hole in the bottom that will be meant to take either a 1/4-20 UNC or 3/8-16 UNC threaded screw.

Most attachments for this will either come with both types of screws or will necessitate the use of an adapter if what the item comes with is not fit to your camera. This monopod, for example, has a reversible screw for both. Point is, these attachments are standardized so the tripod world is your oyster, so to speak.

The quick release plate will attach to your camera via one of these screws – so you can use the same plate across any of your cameras. Or, if you’re lazy like me, you’ll buy extra plates and just keep ’em on your bodies.

The plate will be designed to fit whatever head you’re using. They could be custom designed for the head or could be something more standard, like the Arca-Swiss style plate.

That being said, I’ve never tried to mix brands and I have heard stories of one brand’s arca-swiss plate not quite meshing well with another’s arca-swiss head, even though those should be universal.

To summarize – because of the universality of the attachment screw, don’t let this impact your tripod head decision. Buy that for the features you want and then worry about the attachment, whether you need an adapter or not.

If you want universality in the QR plates, then go for a head that supports Arca-Swiss style plates. Though again, be warned that that is no guarantee of a great meshing between the head and plate if you choose to mix brands.