mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	Break picture handling code from C++ to C.
This commit breaks the loading of images that were done in the divelist into smaller bits. A bit of code refactor was done in order to correct the placement of a few methods. ShiftTimesDialog::EpochFromExiv got moved to Exif::epoch dive_add_picture is now used instead of add_event picture_load_exif_data got implemented using the old listview code. dive_set_geodata_from_picture got implemented using the old listview code. Signed-off-by: Tomaz Canabrava <tomaz.canabrava@intel.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
		
							parent
							
								
									13e8aba7da
								
							
						
					
					
						commit
						d95d1735b5
					
				
					 9 changed files with 87 additions and 70 deletions
				
			
		| 
						 | 
					@ -106,6 +106,7 @@ SET(SUBSURFACE_CORE_LIB_SRCS
 | 
				
			||||||
	#dirk ported some core functionality to c++.
 | 
						#dirk ported some core functionality to c++.
 | 
				
			||||||
	qthelper.cpp
 | 
						qthelper.cpp
 | 
				
			||||||
	divecomputer.cpp
 | 
						divecomputer.cpp
 | 
				
			||||||
 | 
						exif.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#the interface, in C++
 | 
					#the interface, in C++
 | 
				
			||||||
| 
						 | 
					@ -132,7 +133,6 @@ SET(SUBSURFACE_INTERFACE
 | 
				
			||||||
	qt-ui/starwidget.cpp
 | 
						qt-ui/starwidget.cpp
 | 
				
			||||||
	qt-ui/subsurfacewebservices.cpp
 | 
						qt-ui/subsurfacewebservices.cpp
 | 
				
			||||||
	qt-ui/tableview.cpp
 | 
						qt-ui/tableview.cpp
 | 
				
			||||||
	qt-ui/exif.cpp
 | 
					 | 
				
			||||||
	qt-ui/divelogimportdialog.cpp
 | 
						qt-ui/divelogimportdialog.cpp
 | 
				
			||||||
	qt-ui/tagwidget.cpp
 | 
						qt-ui/tagwidget.cpp
 | 
				
			||||||
	qt-ui/groupedlineedit.cpp
 | 
						qt-ui/groupedlineedit.cpp
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										30
									
								
								dive.c
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								dive.c
									
										
									
									
									
								
							| 
						 | 
					@ -2260,14 +2260,26 @@ int average_depth(struct diveplan *dive)
 | 
				
			||||||
	return integral / last_time;
 | 
						return integral / last_time;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void picture_load_exif_data(struct picture *p)
 | 
					struct picture *alloc_picture()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct picture *pic = malloc(sizeof(struct picture));
 | 
				
			||||||
 | 
						if (!pic)
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
						memset(pic, 0, sizeof(struct picture));
 | 
				
			||||||
 | 
						return pic;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct picture* dive_add_picture(struct dive *d, char *picture)
 | 
					void dive_add_picture(struct dive *d, struct picture *picture)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (d->picture_list == NULL) {
 | 
				
			||||||
 | 
							d->picture_list = picture;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						struct picture *last = d->picture_list;
 | 
				
			||||||
 | 
						while( last->next )
 | 
				
			||||||
 | 
							last = last->next;
 | 
				
			||||||
 | 
						last->next = picture;
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint dive_get_picture_count(struct dive *d)
 | 
					uint dive_get_picture_count(struct dive *d)
 | 
				
			||||||
| 
						 | 
					@ -2278,7 +2290,15 @@ uint dive_get_picture_count(struct dive *d)
 | 
				
			||||||
	return i;
 | 
						return i;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dive_remove_picture(struct dive *d, char *picture)
 | 
					void dive_set_geodata_from_picture(struct dive *d, struct picture *pic)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!d->latitude.udeg && pic->latitude.udeg) {
 | 
				
			||||||
 | 
							d->latitude = pic->latitude;
 | 
				
			||||||
 | 
							d->longitude = pic->longitude;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void dive_remove_picture(struct dive *d, struct picture *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								dive.h
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								dive.h
									
										
									
									
									
								
							| 
						 | 
					@ -286,16 +286,21 @@ struct dive {
 | 
				
			||||||
struct picture {
 | 
					struct picture {
 | 
				
			||||||
	char *filename;
 | 
						char *filename;
 | 
				
			||||||
	time_t timestamp;
 | 
						time_t timestamp;
 | 
				
			||||||
 | 
						degrees_t latitude;
 | 
				
			||||||
 | 
						degrees_t longitude;
 | 
				
			||||||
	struct picture *next;
 | 
						struct picture *next;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define FOR_EACH_PICTURE( DIVE ) \
 | 
					#define FOR_EACH_PICTURE( DIVE ) \
 | 
				
			||||||
	for(struct picture *picture = DIVE->picture_list; picture; picture = picture->next)
 | 
						for(struct picture *picture = DIVE->picture_list; picture; picture = picture->next)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct picture *dive_add_picture(struct dive *d, char *picture);
 | 
					
 | 
				
			||||||
extern void dive_remove_picture(struct dive *d, char *picture);
 | 
					extern struct picture *alloc_picture();
 | 
				
			||||||
 | 
					extern void dive_add_picture(struct dive *d, struct picture *pic);
 | 
				
			||||||
 | 
					extern void dive_remove_picture(struct dive *d, struct picture *pic);
 | 
				
			||||||
extern uint dive_get_picture_count(struct dive *d);
 | 
					extern uint dive_get_picture_count(struct dive *d);
 | 
				
			||||||
extern void picture_load_exif_data(struct picture *p);
 | 
					extern void picture_load_exif_data(struct picture *p);
 | 
				
			||||||
 | 
					extern void dive_set_geodata_from_picture(struct dive *d, struct picture *pic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int dive_has_gps_location(struct dive *dive)
 | 
					static inline int dive_has_gps_location(struct dive *dive)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@
 | 
				
			||||||
     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
					     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include "dive.h"
 | 
				
			||||||
#include "exif.h"
 | 
					#include "exif.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using std::string;
 | 
					using std::string;
 | 
				
			||||||
| 
						 | 
					@ -566,3 +567,21 @@ void EXIFInfo::clear()
 | 
				
			||||||
	GeoLocation.LonComponents.seconds = 0;
 | 
						GeoLocation.LonComponents.seconds = 0;
 | 
				
			||||||
	GeoLocation.LonComponents.direction = 0;
 | 
						GeoLocation.LonComponents.direction = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					time_t EXIFInfo::epoch()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tm tm;
 | 
				
			||||||
 | 
						int year, month, day, hour, min, sec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (DateTimeOriginal.size())
 | 
				
			||||||
 | 
							sscanf(DateTimeOriginal.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							sscanf(DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
 | 
				
			||||||
 | 
						tm.tm_year = year;
 | 
				
			||||||
 | 
						tm.tm_mon = month - 1;
 | 
				
			||||||
 | 
						tm.tm_mday = day;
 | 
				
			||||||
 | 
						tm.tm_hour = hour;
 | 
				
			||||||
 | 
						tm.tm_min = min;
 | 
				
			||||||
 | 
						tm.tm_sec = sec;
 | 
				
			||||||
 | 
						return (utc_mktime(&tm));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -129,6 +129,8 @@ public:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		clear();
 | 
							clear();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						time_t epoch();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parse was successful
 | 
					// Parse was successful
 | 
				
			||||||
| 
						 | 
					@ -764,63 +764,33 @@ void DiveListView::shiftTimes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DiveListView::loadImages()
 | 
					void DiveListView::loadImages()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct memblock mem;
 | 
					 | 
				
			||||||
	EXIFInfo exif;
 | 
					 | 
				
			||||||
	int retval;
 | 
					 | 
				
			||||||
	time_t imagetime;
 | 
					 | 
				
			||||||
	struct divecomputer *dc;
 | 
					 | 
				
			||||||
	time_t when;
 | 
					 | 
				
			||||||
	int duration_s;
 | 
					 | 
				
			||||||
	QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Image Files"), lastUsedImageDir(), tr("Image Files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
 | 
						QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Image Files"), lastUsedImageDir(), tr("Image Files (*.jpg *.jpeg *.pnm *.tif *.tiff)"));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (fileNames.isEmpty())
 | 
						if (fileNames.isEmpty())
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	updateLastUsedImageDir(QFileInfo(fileNames[0]).dir().path());
 | 
						updateLastUsedImageDir(QFileInfo(fileNames[0]).dir().path());
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ShiftImageTimesDialog shiftDialog(this);
 | 
						ShiftImageTimesDialog shiftDialog(this);
 | 
				
			||||||
	shiftDialog.setOffset(lastImageTimeOffset());
 | 
						shiftDialog.setOffset(lastImageTimeOffset());
 | 
				
			||||||
	shiftDialog.exec();
 | 
						shiftDialog.exec();
 | 
				
			||||||
	updateLastImageTimeOffset(shiftDialog.amount());
 | 
						updateLastImageTimeOffset(shiftDialog.amount());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < fileNames.size(); ++i) {
 | 
						Q_FOREACH(const QString& fileName, fileNames) {
 | 
				
			||||||
		if (readfile(fileNames.at(i).toUtf8().data(), &mem) <= 0)
 | 
							picture *p = alloc_picture();
 | 
				
			||||||
			continue;
 | 
							p->filename = qstrdup(fileName.toUtf8().data());
 | 
				
			||||||
		//TODO: This inner code should be ported to C-Code.
 | 
							picture_load_exif_data(p);
 | 
				
			||||||
		retval = exif.parseFrom((const unsigned char *)mem.buffer, (unsigned)mem.size);
 | 
					
 | 
				
			||||||
		free(mem.buffer);
 | 
							if (p->timestamp)
 | 
				
			||||||
		if (retval != PARSE_EXIF_SUCCESS)
 | 
								p->timestamp += shiftDialog.amount(); // TODO: this should be cached and passed to the C-function
 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		imagetime = shiftDialog.epochFromExiv(&exif);
 | 
					 | 
				
			||||||
		if (!imagetime)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		imagetime += shiftDialog.amount(); // TODO: this should be cached and passed to the C-function
 | 
					 | 
				
			||||||
		int j = 0;
 | 
							int j = 0;
 | 
				
			||||||
		struct dive *dive;
 | 
							struct dive *dive;
 | 
				
			||||||
		for_each_dive (j, dive) {
 | 
							for_each_dive (j, dive) {
 | 
				
			||||||
			if (!dive->selected)
 | 
								if (!dive->selected)
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			for_each_dc (dive, dc) {
 | 
								dive_add_picture(dive, p);
 | 
				
			||||||
				when = dc->when ? dc->when : dive->when;
 | 
								dive_set_geodata_from_picture(dive, p);
 | 
				
			||||||
				duration_s = dc->duration.seconds ? dc->duration.seconds : dive->duration.seconds;
 | 
					 | 
				
			||||||
				if (when - 3600 < imagetime && when + duration_s + 3600 > imagetime) {
 | 
					 | 
				
			||||||
					if (when > imagetime) {
 | 
					 | 
				
			||||||
						// Before dive
 | 
					 | 
				
			||||||
						add_event(dc, 0, 123, 0, 0, fileNames.at(i).toUtf8().data());
 | 
					 | 
				
			||||||
					} else if (when + duration_s < imagetime) {
 | 
					 | 
				
			||||||
						// After dive
 | 
					 | 
				
			||||||
						add_event(dc, duration_s, 123, 0, 0, fileNames.at(i).toUtf8().data());
 | 
					 | 
				
			||||||
					} else {
 | 
					 | 
				
			||||||
						add_event(dc, imagetime - when, 123, 0, 0, fileNames.at(i).toUtf8().data());
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					if (!dive->latitude.udeg && !IS_FP_SAME(exif.GeoLocation.Latitude, 0.0)) {
 | 
					 | 
				
			||||||
						dive->latitude.udeg = lrint(1000000.0 * exif.GeoLocation.Latitude);
 | 
					 | 
				
			||||||
						dive->longitude.udeg = lrint(1000000.0 * exif.GeoLocation.Longitude);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mark_divelist_changed(true);
 | 
						mark_divelist_changed(true);
 | 
				
			||||||
	MainWindow::instance()->refreshDisplay();
 | 
						MainWindow::instance()->refreshDisplay();
 | 
				
			||||||
	MainWindow::instance()->graphics()->replot();
 | 
						MainWindow::instance()->graphics()->replot();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -247,31 +247,12 @@ void ShiftImageTimesDialog::syncCameraClicked()
 | 
				
			||||||
	free(mem.buffer);
 | 
						free(mem.buffer);
 | 
				
			||||||
	if (retval != PARSE_EXIF_SUCCESS)
 | 
						if (retval != PARSE_EXIF_SUCCESS)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	dcImageEpoch = epochFromExiv(&exiv);
 | 
						dcImageEpoch = exiv.epoch();
 | 
				
			||||||
	dcDateTime.setTime_t(dcImageEpoch);
 | 
						dcDateTime.setTime_t(dcImageEpoch);
 | 
				
			||||||
	ui.dcTime->setDateTime(dcDateTime);
 | 
						ui.dcTime->setDateTime(dcDateTime);
 | 
				
			||||||
	connect(ui.dcTime, SIGNAL(dateTimeChanged(const QDateTime &)), this, SLOT(dcDateTimeChanged(const QDateTime &)));
 | 
						connect(ui.dcTime, SIGNAL(dateTimeChanged(const QDateTime &)), this, SLOT(dcDateTimeChanged(const QDateTime &)));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//TODO: This should be moved to C-Code.
 | 
					 | 
				
			||||||
time_t ShiftImageTimesDialog::epochFromExiv(EXIFInfo *exif)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct tm tm;
 | 
					 | 
				
			||||||
	int year, month, day, hour, min, sec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (strlen(exif->DateTimeOriginal.c_str()))
 | 
					 | 
				
			||||||
		sscanf(exif->DateTimeOriginal.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		sscanf(exif->DateTime.c_str(), "%d:%d:%d %d:%d:%d", &year, &month, &day, &hour, &min, &sec);
 | 
					 | 
				
			||||||
	tm.tm_year = year;
 | 
					 | 
				
			||||||
	tm.tm_mon = month - 1;
 | 
					 | 
				
			||||||
	tm.tm_mday = day;
 | 
					 | 
				
			||||||
	tm.tm_hour = hour;
 | 
					 | 
				
			||||||
	tm.tm_min = min;
 | 
					 | 
				
			||||||
	tm.tm_sec = sec;
 | 
					 | 
				
			||||||
	return (utc_mktime(&tm));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ShiftImageTimesDialog::dcDateTimeChanged(const QDateTime &newDateTime)
 | 
					void ShiftImageTimesDialog::dcDateTimeChanged(const QDateTime &newDateTime)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!dcImageEpoch)
 | 
						if (!dcImageEpoch)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								qthelper.cpp
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								qthelper.cpp
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,8 @@
 | 
				
			||||||
#include "qthelper.h"
 | 
					#include "qthelper.h"
 | 
				
			||||||
#include "qt-gui.h"
 | 
					#include "qt-gui.h"
 | 
				
			||||||
 | 
					#include "dive.h"
 | 
				
			||||||
 | 
					#include <exif.h>
 | 
				
			||||||
 | 
					#include "file.h"
 | 
				
			||||||
#include <QRegExp>
 | 
					#include <QRegExp>
 | 
				
			||||||
#include <QDir>
 | 
					#include <QDir>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -260,3 +263,20 @@ extern "C" xsltStylesheetPtr get_stylesheet(const char *name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return xslt;
 | 
						return xslt;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" void picture_load_exif_data(struct picture *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						EXIFInfo exif;
 | 
				
			||||||
 | 
						memblock mem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (readfile(p->filename, &mem) <= 0)
 | 
				
			||||||
 | 
							goto picture_load_exit;
 | 
				
			||||||
 | 
						if (exif.parseFrom((const unsigned char *)mem.buffer, (unsigned)mem.size) != PARSE_EXIF_SUCCESS)
 | 
				
			||||||
 | 
							goto picture_load_exit;
 | 
				
			||||||
 | 
						p->timestamp = exif.epoch();
 | 
				
			||||||
 | 
						p->longitude.udeg= lrint(1000000.0 * exif.GeoLocation.Longitude);
 | 
				
			||||||
 | 
						p->latitude.udeg  = lrint(1000000.0 * exif.GeoLocation.Latitude);
 | 
				
			||||||
 | 
						picture_load_exit:
 | 
				
			||||||
 | 
							free(mem.buffer);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,7 @@ HEADERS = \
 | 
				
			||||||
	qt-ui/starwidget.h \
 | 
						qt-ui/starwidget.h \
 | 
				
			||||||
	qt-ui/subsurfacewebservices.h \
 | 
						qt-ui/subsurfacewebservices.h \
 | 
				
			||||||
	qt-ui/tableview.h \
 | 
						qt-ui/tableview.h \
 | 
				
			||||||
	qt-ui/exif.h \
 | 
						exif.h \
 | 
				
			||||||
	sha1.h \
 | 
						sha1.h \
 | 
				
			||||||
	statistics.h \
 | 
						statistics.h \
 | 
				
			||||||
	subsurfacestartup.h \
 | 
						subsurfacestartup.h \
 | 
				
			||||||
| 
						 | 
					@ -131,7 +131,7 @@ SOURCES =  \
 | 
				
			||||||
	qt-ui/starwidget.cpp \
 | 
						qt-ui/starwidget.cpp \
 | 
				
			||||||
	qt-ui/subsurfacewebservices.cpp \
 | 
						qt-ui/subsurfacewebservices.cpp \
 | 
				
			||||||
	qt-ui/tableview.cpp \
 | 
						qt-ui/tableview.cpp \
 | 
				
			||||||
	qt-ui/exif.cpp \
 | 
						exif.cpp \
 | 
				
			||||||
	save-git.c \
 | 
						save-git.c \
 | 
				
			||||||
	save-xml.c \
 | 
						save-xml.c \
 | 
				
			||||||
	sha1.c \
 | 
						sha1.c \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue