From 5c04a7368c1e4e12005925ae79a9ab0a3b7a91b3 Mon Sep 17 00:00:00 2001 From: taynpg Date: Sun, 5 May 2024 22:55:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E7=89=88=E8=BD=AC=E6=88=90cmake?= =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clang-format | 38 ++ .clangd | 12 + .gitignore | 3 + .vscode/qt5.natvis | 814 ++++++++++++++++++++++++++++++++++++++++++ .vscode/qt6.natvis | 735 ++++++++++++++++++++++++++++++++++++++ .vscode/settings.json | 38 ++ CMakeLists.txt | 83 +++++ LICENSE | 201 +++++++++++ README.md | 21 ++ src/ConfigOpr.cpp | 161 +++++++++ src/ConfigOpr.h | 50 +++ src/FTPTrans.cpp | 232 ++++++++++++ src/FTPTrans.h | 29 ++ src/FTPTrans.ico | Bin 0 -> 370070 bytes src/FTPTrans.qrc | 4 + src/FTPTrans.rc | 1 + src/FTPTrans.ui | 156 ++++++++ src/main.cpp | 14 + 18 files changed, 2592 insertions(+) create mode 100644 .clang-format create mode 100644 .clangd create mode 100644 .gitignore create mode 100644 .vscode/qt5.natvis create mode 100644 .vscode/qt6.natvis create mode 100644 .vscode/settings.json create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 src/ConfigOpr.cpp create mode 100644 src/ConfigOpr.h create mode 100644 src/FTPTrans.cpp create mode 100644 src/FTPTrans.h create mode 100644 src/FTPTrans.ico create mode 100644 src/FTPTrans.qrc create mode 100644 src/FTPTrans.rc create mode 100644 src/FTPTrans.ui create mode 100644 src/main.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..18fbbc4 --- /dev/null +++ b/.clang-format @@ -0,0 +1,38 @@ +# .clang-format + +# 风格格式化 +BasedOnStyle: LLVM +# 4 空格缩进 +IndentWidth: 4 +# 连续对齐变量的声明 +AlignConsecutiveDeclarations: true +# 指针左侧对齐 +PointerAlignment: Left +# 访问说明符(public、private等)的偏移 +AccessModifierOffset: -4 +# 大括号 +BreakBeforeBraces: Custom +BraceWrapping: + # 函数定义后面大括号在新行 + AfterFunction: true + # class定义后面 + AfterClass: true + +# 去除C++11的列表初始化的大括号{后和}前的空格 +Cpp11BracedListStyle: true +# 允许重新排版注释 +ReflowComments: true +# 允许排序#include +SortIncludes: true +# 在尾随的评论前添加的空格数(只适用于//) +SpacesBeforeTrailingComments: 3 +# tab宽度 +TabWidth: 4 +# 构造函数的初始化列表要么都在同一行,要么都各自一行 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +# 每行字符的限制,0表示没有限制 +ColumnLimit: 150 +# 允许短的块放在同一行 +AllowShortBlocksOnASingleLine: false +# 是否允许短函数在一行 +AllowShortFunctionsOnASingleLine: InlineOnly \ No newline at end of file diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..11d6e06 --- /dev/null +++ b/.clangd @@ -0,0 +1,12 @@ +Hover: + ShowAKA: Yes +Diagnostics: + UnusedIncludes: None # 禁用未使用头文件提示 + Suppress: [ + anon_type_definition, # 禁用匿名的typedef提示 + unused-variable, # 禁用未使用变量提示 + unused-function, # 禁用未使用函数提示 + unused-includes, # 禁用未使用的头文件提示 + ] + ClangTidy: + Remove: misc-unused-alias-decls diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ff8bda6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +.vs +.cache \ No newline at end of file diff --git a/.vscode/qt5.natvis b/.vscode/qt5.natvis new file mode 100644 index 0000000..7d18567 --- /dev/null +++ b/.vscode/qt5.natvis @@ -0,0 +1,814 @@ + + + + + + + {{{data1,Xb}-{data2,Xb}-{data3,Xb}-{(data4[0]),nvoXb}{(data4[1]),nvoXb}-{(data4[2]),nvoXb}{(data4[3]),nvoXb}{(data4[4]),nvoXb}{(data4[5]),nvoXb}{(data4[6]),nvoXb}{(data4[7]),nvoXb}}} + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {x1}, y = {y1}, width = {x2 - x1 + 1}, height = {y2 - y1 + 1} }} + + x1 + y1 + x2 - x1 + 1 + y2 - y1 + 1 + + + + + {{ x = {xp}, y = {yp}, width = {w}, height = {h} }} + + xp + yp + w + h + + + + + + {{ width = {wd}, height = {ht} }} + + wd + ht + + + + + + {{ start point = {pt1}, end point = {pt2} }} + + + {pt1} + + pt1 + + + + {pt2} + + pt2 + + + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + (QPoint*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ size = {d->size} }} + + + d->size > 0 + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).xp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).xp) + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).yp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).yp) + + d->ref.atomic._q_value + + d->size + (QPointF*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {xp}, y = {yp}, z = {zp} }} + + xp + yp + zp + + + + + {{ x = {xp}, y = {yp}, z = {zp}, w = {wp} }} + + xp + yp + zp + wp + + + + + + {{ m11 = {_m11}, m12 = {_m12}, m21 = {_m21}, m22 = {_m22}, ... }} + + + _m11 + _m12 + _m21 + _m22 + _dx + _dy + + + + + + {{ m11 = {m[0][0]}, m12 = {m[1][0]}, m13 = {m[2][0]}, m14 = {m[3][0]}, ... }} + + + m[0][0] + m[1][0] + m[2][0] + m[3][0] + m[0][1] + m[1][1] + m[2][1] + m[3][1] + m[0][2] + m[1][2] + m[2][2] + m[3][2] + m[0][3] + m[1][3] + m[2][3] + m[3][3] + + + + + + {{ horizontal = {static_cast<Policy>(bits.horPolicy)}, vertical = {static_cast<Policy>(bits.verPolicy)}, type = {ControlType(1 << bits.ctype)} }} + + + + QSizePolicy::Policy::{static_cast<Policy>(bits.verPolicy)} + + + QSizePolicy::Policy::{static_cast<Policy>(bits.horPolicy)} + + + QSizePolicy::ControlType::{ControlType(1 << bits.ctype)} + + + + Qt::Vertical (2) + + + Qt::Horizontal (1) + + + static_cast<int>(bits.verStretch) + static_cast<int>(bits.horStretch) + bits.hfw == 1 + bits.wfh == 1 + + + + + {ucs,c} + ucs,c + + ucs > 0xff ? '\0' : char(ucs),c + ucs,c + + + + + {((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),sub} + ((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),sub + + d->size + d->ref.atomic._q_value + + d->size + ((reinterpret_cast<unsigned short*>(d)) + d->offset / 2),c + + + + + + + {m_string,[m_size]} u"" + {offset() + m_position,[m_size]} + + m_position + m_size + + m_size + offset()+m_position + + + + + + {m_data,[m_size]} + m_data,[m_size] + + m_size + + m_size + m_data + + + + + + {((reinterpret_cast<char*>(d)) + d->offset),sb} + ((reinterpret_cast<char*>(d)) + d->offset),sb + + d->size + d->ref.atomic._q_value + + d->size + ((reinterpret_cast<char*>(d)) + d->offset),c + + + + + + + + + + + + + + + + + + + + {scheme()}://{host()}{path()} + {path()} + + scheme() + username() + password() + host() + path() + query() + fragment() + + + + + {{ size = {(d.d->size << 3) - *((reinterpret_cast<char*>(d.d)) + d.d->offset)} }} + + d.d->ref.atomic._q_value + + (d.d->size << 3) - *((reinterpret_cast<char*>(d.d)) + d.d->offset) + + (*(reinterpret_cast<const unsigned char*>((reinterpret_cast<char*>(d.d)) + d.d->offset) + 1 + + ($i >> 3)) & (1 << ($i & 7))) != 0 + + + + + + + + {{ size = {s} }} + + a + + s + ptr + + + + + + {{ julian day = {jd} }} + + + + + {{ millisecond = {mds} }} + {{ milliseconds = {mds} }} + + mds / 3600000, d + mds / 3600000, d + (mds % 3600000) / 60000, d + (mds % 3600000) / 60000, d + (mds / 1000) % 60, d + (mds / 1000) % 60, d + mds % 1000, d + mds % 1000, d + + + + + {d.pattern} + + + + + ref._q_value + + + + + strong reference to shared pointer of type {"$T1"} + + value == 0 + d->weakref._q_value + d->strongref._q_value + + + + + pointer to implicit shared object of type {"$T1"} + + d + + + + + pointer to explicit shared object of type {"$T1"} + + d + + + + + guarded pointer to subclass of QObject of type {"$T1"} + + wp.d == 0 || wp.d->strongref._q_value == 0 || wp.value == 0 + + + + + weak reference to shared pointer of type {"$T1"} + + d == 0 || d->strongref._q_value == 0 || value == 0 + d->weakref._q_value + d->strongref._q_value + + + + + scoped pointer to a dynamically allocated object of type {"$T1"} + + !d + + + + + scoped pointer to dynamically allocated array of objects of type {"$T1"} + + !d + + + + + ({first}, {second}) + + first + second + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + ($T1*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + + {{ size = {d->end - d->begin} }} + + d->ref.atomic._q_value + + d->end - d->begin + *reinterpret_cast<$T1*>((sizeof($T1) > sizeof(void*)) + ? reinterpret_cast<Node*>(d->array + d->begin + $i)->v + : reinterpret_cast<$T1*>(d->array + d->begin + $i)) + + + + + + + {{ size = {d->end - d->begin} }} + + d->ref.atomic._q_value + + d->end - d->begin + + *reinterpret_cast<QString*>((sizeof(QString) > sizeof(void*)) + ? reinterpret_cast<Node*>(d->array + d->begin + $i)->v + : reinterpret_cast<QString*>(d->array + d->begin + $i)) + + + + + + + {{ size = {d->end - d->begin} }} + + d->ref.atomic._q_value + + d->end - d->begin + + *reinterpret_cast<QVariant*>((sizeof(QVariant) > sizeof(void*)) + ? reinterpret_cast<Node*>(d->array + d->begin + $i)->v + : reinterpret_cast<QVariant*>(d->array + d->begin + $i)) + + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + d->n + n + (*(QLinkedListNode<$T1>*)this).t + + + + + + ({key}, {value}) + + key + value + + + + + + {{ size = {d->size} }} + + d->ref.atomic._q_value + + d->size + d->header.left + left + right + *((QMapNode<$T1,$T2>*)this) + + + + + + (empty) + ({key}, {value}) + + key + value + next + + + + + + {{ size = {d->size} }} + + + d->numBuckets + reinterpret_cast<Node **>(d->buckets) + + + + + + + d->size + + + node = *(bucket++) + --n + + + keyValuePair = reinterpret_cast<Node *>(node) + keyValuePair->value + node = node->next + + + + + + + + (empty) + ({key}) + + key + + + + + {{ size = {q_hash.d->size} }} + + q_hash + + + + + ({*keyPtr}, {*t}) + + *keyPtr + *t + + + + + {{ size = {hash.d->size} }} + + mx + total + hash.d->ref.atomic._q_value + + hash.d->size + f + n + *((Node*)this) + + + + + + + + + + + + + + {{ row count = {(*d_ptr.d).rows()}, column count = {(*d_ptr.d).columns()} }} + + d_ptr.d,! + (*d_ptr.d).rows() + (*d_ptr.d).columns() + + + + + + + Invalid + {d.data.b} + {d.data.i} + {d.data.u} + {d.data.ll} + {d.data.ull} + {d.data.d} + {d.data.c} + + {*((QMap<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QList<QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QString*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QStringList*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QByteArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QBitArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QDate*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QTime*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + DateTime + Url + Locale + + {*((QRect*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QRectF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QSize*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QSizeF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QLine*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QLineF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QPoint*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + + {*((QPointF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + RegExp + RegularExpression + + {*((QHash<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr)))} + + EasingCurve + Uuid + ModelIndex + LastCoreType + Font + Pixmap + Brush + Color + Palette + Image + Polygon + Region + Bitmap + Cursor + KeySequence + Pen + TextLength + TextFormat + Matrix + Transform + Matrix4x4 + Vector2D + Vector3D + Vector4D + Quaternion + PolygonF + Icon + LastGuiType + SizePolicy + UserType + LastType + + + + + + d.data.c + + + *((QString*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + + *((QByteArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + + + + + + + *((QMap<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QList<QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QString*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QStringList*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QByteArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QBitArray*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QDate*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QTime*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QRect*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QRectF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QSize*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QSizeF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QLine*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QLineF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QPoint*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QPointF*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + *((QHash<QString,QVariant>*)(d.is_shared ? d.data.shared->ptr + : reinterpret_cast<const void *>(&d.data.ptr))) + + + + + + + diff --git a/.vscode/qt6.natvis b/.vscode/qt6.natvis new file mode 100644 index 0000000..94c2260 --- /dev/null +++ b/.vscode/qt6.natvis @@ -0,0 +1,735 @@ + + + + + + + {val} + + val + + + + + + + + {{ x = {x,g}, y = {y,g}, z = {_extraData().z,g}, width = {width,g}, height = {height,g} }} + {{ x = {x,g}, y = {y,g}, width = {width,g}, height = {height,g} }} + + x + y + _extraData().z + _extraData().scale + _extraData().rotation + _extraData().opacity + width + height + implicitWidth + implicitHeight + effectiveVisible + explicitEnable + _objectName(),na + parentItem + childItems, nr + + + + + {d_ptr.d,na} + + d_ptr.d + + + + + {{{data1,Xb}-{data2,Xb}-{data3,Xb}-{(data4[0]),nvoXb}{(data4[1]),nvoXb}-{(data4[2]),nvoXb}{(data4[3]),nvoXb}{(data4[4]),nvoXb}{(data4[5]),nvoXb}{(data4[6]),nvoXb}{(data4[7]),nvoXb}}} + + + + {val} + + val + + + + + {_q_value} + + _q_value + + + + + + + empty + {_q_value} + + *value() + + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {x1}, y = {y1}, width = {x2 - x1 + 1}, height = {y2 - y1 + 1} }} + + x1 + y1 + x2 - x1 + 1 + y2 - y1 + 1 + + + + + {{ x = {xp}, y = {yp}, width = {w}, height = {h} }} + + xp + yp + w + h + + + + + + {{ width = {wd}, height = {ht} }} + + wd + ht + + + + + + {{ start point = {pt1}, end point = {pt2} }} + + + {pt1} + + pt1 + + + + {pt2} + + pt2 + + + + + + + + {{ size={d->size} }} + + d->ref.atomic._q_value + + d->size + (QPoint*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ size={d->size} }} + + + d->size > 0 + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).xp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).xp) + && ((((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[0]).yp + == (((QPointF*)((reinterpret_cast<char*>(d)) + d->offset)[d->size - 1]).yp) + + d->ref.atomic._q_value + + d->size + (QPointF*)((reinterpret_cast<char*>(d)) + d->offset) + + + + + + {{ x = {xp}, y = {yp} }} + + xp + yp + + + + + {{ x = {xp}, y = {yp}, z = {zp} }} + + xp + yp + zp + + + + + {{ x = {xp}, y = {yp}, z = {zp}, w = {wp} }} + + xp + yp + zp + wp + + + + + + {{ m11 = {_m11}, m12 = {_m12}, m21 = {_m21}, m22 = {_m22}, ... }} + + + _m11 + _m12 + _m21 + _m22 + _dx + _dy + + + + + + {{ m11 = {m[0][0]}, m12 = {m[1][0]}, m13 = {m[2][0]}, m14 = {m[3][0]}, ... }} + + + m[0][0] + m[1][0] + m[2][0] + m[3][0] + m[0][1] + m[1][1] + m[2][1] + m[3][1] + m[0][2] + m[1][2] + m[2][2] + m[3][2] + m[0][3] + m[1][3] + m[2][3] + m[3][3] + + + + + + {{ horizontal = {static_cast<Policy>(bits.horPolicy)}, vertical = {static_cast<Policy>(bits.verPolicy)}, type = {ControlType(1 << bits.ctype)} }} + + + + QSizePolicy::Policy::{static_cast<Policy>(bits.verPolicy)} + + + QSizePolicy::Policy::{static_cast<Policy>(bits.horPolicy)} + + + QSizePolicy::ControlType::{ControlType(1 << bits.ctype)} + + + + Qt::Vertical (2) + + + Qt::Horizontal (1) + + + static_cast<int>(bits.verStretch) + static_cast<int>(bits.horStretch) + bits.hfw == 1 + bits.wfh == 1 + + + + + {ucs,c} + ucs,c + + ucs > 0xff ? '\0' : char(ucs),c + ucs,c + + + + + "{(reinterpret_cast<unsigned short*>(d.ptr)),sub}" + (reinterpret_cast<unsigned short*>(d.ptr)),sub + + d.size + + d.size + d.ptr + + + + + + {m_string,[m_size]} u"" + {m_string->d.ptr+m_position,[m_size]} + "" + m_string,[m_position+m_size] + + m_position + m_size + + m_size + m_string->d.ptr+m_position + + + + + + {m_data,[m_size]} + m_data,[m_size] + + m_size + + m_size + m_data + + + + + + "{((reinterpret_cast<char*>(d.ptr))),sb}" + ((reinterpret_cast<char*>(d.ptr))),sb + + d.size + + d.size + d.ptr + + + + + + + + + + + + + + + + + + + + {scheme()}://{host()}{path()} + {path()} + + scheme() + username() + password() + host() + path() + query() + fragment() + + + + + {{ julian day = {jd} }} + + + + + + + + {{ millisecond = {mds} }} + {{ milliseconds = {mds} }} + + hour(), d + hour(), d + minute(), d + minute(), d + second(), d + second(), d + millisecond(), d + millisecond(), d + + + + + ({first}, {second}) + + first + second + + + + + + {{ size={d.size} }} + + + d.size + reinterpret_cast<$T1*>(d.ptr) + + + + + + {{ size={s} }} + + a + + s + ptr + + + + + + + {{ size={d.d->m._Mypair._Myval2._Myval2._Mysize} }} + + + d.d->m._Mypair._Myval2._Myval2._Mysize + d.d->m._Mypair._Myval2._Myval2._Myhead->_Parent + _Left + _Right + _Myval,view(MapHelper) + + + + + + {second} + + + + {value} + + key + value + + + + + {value->value} + ({value->value}, {value->next->value}) + ({value->value}, {value->next->value}, ...) + + + value + next + value + + + + + + + + + + + + + + + + + + + + {{ size={d->size} }} + + + + + d->size + + + getNode(iSpan, 0) + getNode(iSpan, 1) + getNode(iSpan, 2) + getNode(iSpan, 3) + getNode(iSpan, 4) + getNode(iSpan, 5) + getNode(iSpan, 6) + getNode(iSpan, 7) + getNode(iSpan, 8) + getNode(iSpan, 9) + getNode(iSpan, 10) + getNode(iSpan, 11) + getNode(iSpan, 12) + getNode(iSpan, 13) + getNode(iSpan, 14) + getNode(iSpan, 15) + getNode(iSpan, 16) + getNode(iSpan, 17) + getNode(iSpan, 18) + getNode(iSpan, 19) + getNode(iSpan, 20) + getNode(iSpan, 21) + getNode(iSpan, 22) + getNode(iSpan, 23) + getNode(iSpan, 24) + getNode(iSpan, 25) + getNode(iSpan, 26) + getNode(iSpan, 27) + getNode(iSpan, 28) + getNode(iSpan, 29) + getNode(iSpan, 30) + getNode(iSpan, 31) + getNode(iSpan, 32) + getNode(iSpan, 33) + getNode(iSpan, 34) + getNode(iSpan, 35) + getNode(iSpan, 36) + getNode(iSpan, 37) + getNode(iSpan, 38) + getNode(iSpan, 39) + getNode(iSpan, 40) + getNode(iSpan, 41) + getNode(iSpan, 42) + getNode(iSpan, 43) + getNode(iSpan, 44) + getNode(iSpan, 45) + getNode(iSpan, 46) + getNode(iSpan, 47) + getNode(iSpan, 48) + getNode(iSpan, 49) + getNode(iSpan, 50) + getNode(iSpan, 51) + getNode(iSpan, 52) + getNode(iSpan, 53) + getNode(iSpan, 54) + getNode(iSpan, 55) + getNode(iSpan, 56) + getNode(iSpan, 57) + getNode(iSpan, 58) + getNode(iSpan, 59) + getNode(iSpan, 60) + getNode(iSpan, 61) + getNode(iSpan, 62) + getNode(iSpan, 63) + getNode(iSpan, 64) + getNode(iSpan, 65) + getNode(iSpan, 66) + getNode(iSpan, 67) + getNode(iSpan, 68) + getNode(iSpan, 69) + getNode(iSpan, 70) + getNode(iSpan, 71) + getNode(iSpan, 72) + getNode(iSpan, 73) + getNode(iSpan, 74) + getNode(iSpan, 75) + getNode(iSpan, 76) + getNode(iSpan, 77) + getNode(iSpan, 78) + getNode(iSpan, 79) + getNode(iSpan, 80) + getNode(iSpan, 81) + getNode(iSpan, 82) + getNode(iSpan, 83) + getNode(iSpan, 84) + getNode(iSpan, 85) + getNode(iSpan, 86) + getNode(iSpan, 87) + getNode(iSpan, 88) + getNode(iSpan, 89) + getNode(iSpan, 90) + getNode(iSpan, 91) + getNode(iSpan, 92) + getNode(iSpan, 93) + getNode(iSpan, 94) + getNode(iSpan, 95) + getNode(iSpan, 96) + getNode(iSpan, 97) + getNode(iSpan, 98) + getNode(iSpan, 99) + getNode(iSpan, 100) + getNode(iSpan, 101) + getNode(iSpan, 102) + getNode(iSpan, 103) + getNode(iSpan, 104) + getNode(iSpan, 105) + getNode(iSpan, 106) + getNode(iSpan, 107) + getNode(iSpan, 108) + getNode(iSpan, 109) + getNode(iSpan, 110) + getNode(iSpan, 111) + getNode(iSpan, 112) + getNode(iSpan, 113) + getNode(iSpan, 114) + getNode(iSpan, 115) + getNode(iSpan, 116) + getNode(iSpan, 117) + getNode(iSpan, 118) + getNode(iSpan, 119) + getNode(iSpan, 120) + getNode(iSpan, 121) + getNode(iSpan, 122) + getNode(iSpan, 123) + getNode(iSpan, 124) + getNode(iSpan, 125) + getNode(iSpan, 126) + getNode(iSpan, 127) + iSpan++ + + + + + + + + {{ size={q_hash.d->size} }} + + q_hash + + + + + + + + + + + + (null) + + + QObject* + + + {*(QMap<QString,QVariant>*) sharedDataStar()} + {*(QList<QVariant>*) sharedDataStar()} + {*(QHash<QString,QVariant>*) sharedDataStar()} + QVariantPair + {*(QList<QByteArray>*) sharedDataStar()} + {*(QList<QString>*) sharedDataStar()} + + + {*(bool*) dataStar()} + {*(int*) dataStar()} + {*(unsigned int*) dataStar()} + {*(long long*) dataStar()} + {*(unsigned long long*) dataStar()} + {*(double*) dataStar()} + {*(void**) dataStar()} + {*(long*) dataStar()} + {*(short*) dataStar()} + {*(char*) dataStar()} + {*(char16_t*) dataStar()} + {*(char32_t*) dataStar()} + {*(unsigned long*) dataStar()} + {*(unsigned short*) dataStar()} + {*(unsigned char*) dataStar()} + {*(float*) dataStar()} + {*(signed char*) dataStar()} + + + {*(QChar*) sharedDataStar()} + {*(QString*) sharedDataStar()} + {*(QByteArray*) sharedDataStar()} + {*(QDate*) sharedDataStar()} + {*(QTime*) sharedDataStar()} + QDateTime + QUrl + QLocale + {*(QRect*) sharedDataStar()} + {*(QRectF*) sharedDataStar()} + {*(QSize*) sharedDataStar()} + {*(QSizeF*) sharedDataStar()} + {*(QLine*) sharedDataStar()} + {*(QLineF*) sharedDataStar()} + {*(QPoint*) sharedDataStar()} + {*(QPointF*) sharedDataStar()} + EasingCurve + Uuid + RegularExpression + QJsonValue + QJsonObject + QJsonArray + QJsonDocument + QCborValue + QCborArray + QCborMap + ModelIndex + QPersistentModelIndex + + + QFont + QPixmap + QBrush + QColor + QPalette + QIcon + QImage + QPolygon + QRegion + QBitmap + QCursor + QKeySequence + QPen + QTextLength + QTextFormat + QTransform + QMatrix4x4 + QVector2D + QVector3D + QVector4D + QQuaternion + QPolygonF + QColorSpace + + + QSizePolicy + + + QMetaType::Type ({typeId()}) + + + *(QString*) sharedDataStar() + *(QByteArray*) sharedDataStar() + *(QDate*) sharedDataStar() + *(QTime*) sharedDataStar() + *(QRect*) sharedDataStar() + *(QRectF*) sharedDataStar() + *(QSize*) sharedDataStar() + *(QSizeF*) sharedDataStar() + *(QLine*) sharedDataStar() + *(QLineF*) sharedDataStar() + *(QPoint*) sharedDataStar() + *(QPointF*) sharedDataStar() + + *(QMap<QString,QVariant>*) sharedDataStar() + *(QList<QVariant>*) sharedDataStar() + *(QHash<QString,QVariant>*) sharedDataStar() + *(QList<QByteArray>*) sharedDataStar() + *(QList<QString>*) sharedDataStar() + + + + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..067b8fd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,38 @@ +{ + "files.autoSave": "onFocusChange", + "editor.fontSize": 15, + "editor.fontFamily": "'Operator Mono Lig', 'Operator Mono Lig', 'Operator Mono Lig'", + "cmake.configureOnOpen": true, + "cmake.debugConfig": { + "console": "integratedTerminal", + "visualizerFile": "${workspaceRoot}/.vscode/qt5.natvis" + }, + "cmake.environment": { + "PATH": "${env:PATH};/bin" + }, + "cmake.configureSettings": { + "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + }, + "cmake.options.statusBarVisibility": "visible", + "cmake.generator": "Ninja", + "C_Cpp.intelliSenseEngine": "disabled", + "clangd.arguments": [ + "--header-insertion=never", + "--all-scopes-completion", + "--completion-style=detailed", + "--clang-tidy", + "-j=4", + "--pch-storage=memory", + "--compile-commands-dir=build", + "--background-index", + "--ranking-model=heuristics", + "--function-arg-placeholders=false", + "--query-driver=repaceE" + ], + "editor.inlayHints.enabled": "off", + "editor.unicodeHighlight.allowedLocales": { + "ja": true, + "zh-hant": true, + "zh-hans": true + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5172148 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,83 @@ +cmake_minimum_required(VERSION 3.5) + +project(FTPTrans VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) +find_package(CURL REQUIRED) +find_path(SIMPLEINI_INCLUDE_DIRS ")ConvertUTF.c") + +if (MSVC) + if(${QT_VERSION_MAJOR} LESS 6) + add_compile_options(/source-charset:utf-8) + endif() + add_compile_options(/EHsc) + add_compile_options(-D_CRT_SECURE_NO_WARNINGS) +endif() + +set(PROJECT_SOURCES + src/main.cpp + src/ConfigOpr.cpp src/ConfigOpr.h + src/FTPTrans.h src/FTPTrans.cpp + src/FTPTrans.qrc src/FTPTrans.rc + src/FTPTrans.ui +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(FTPTrans + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET FTPTrans APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation +else() + if(ANDROID) + add_library(FTPTrans SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(FTPTrans + ${PROJECT_SOURCES} + ) + endif() +endif() + +target_link_libraries(FTPTrans PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) +target_link_libraries(FTPTrans PRIVATE CURL::libcurl) +#target_include_directories(FTPTrans PRIVATE ${SIMPLEINI_INCLUDE_DIRS}) + +# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1. +# If you are developing for iOS or macOS you should consider setting an +# explicit, fixed bundle identifier manually though. +if(${QT_VERSION} VERSION_LESS 6.1.0) + set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.FTPTrans) +endif() +set_target_properties(FTPTrans PROPERTIES + ${BUNDLE_ID_OPTION} + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +include(GNUInstallDirs) +install(TARGETS FTPTrans + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(FTPTrans) +endif() diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1770a61 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# FTPTrans + +## 介绍 + +传输文件的FTP工具。 + +## 构建说明 + +- 使用VCPKG,使用`cmake`生成时指定`CMAKE_TOOLCHAIN_FILE`。 + +使用组件有:`curl(8.7.1)`、`simpleini(4.22)`、`qt(5.15.13)`,括号版本是实际在用的版本。 + +```shell +-DCMAKE_TOOLCHAIN_FILE=${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake +``` + +或者 + +```shell +-DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake +``` diff --git a/src/ConfigOpr.cpp b/src/ConfigOpr.cpp new file mode 100644 index 0000000..48de184 --- /dev/null +++ b/src/ConfigOpr.cpp @@ -0,0 +1,161 @@ +#include "ConfigOpr.h" +#include + +constexpr const char* KEY_PWD = "Password"; +constexpr const char* KEY_IP = "IP"; +constexpr const char* KEY_ITEMCNT = "ItemCnt"; +constexpr const char* KEY_USERNAME = "Username"; +constexpr const char* KEY_PORT = "Port"; +constexpr const char* HEAD_BASIC = "Basic"; +constexpr const char* HEAD_ITEM = "Item"; +constexpr const char* KEY_SOURCE = "Source"; +constexpr const char* KEY_DES = "Des"; +constexpr const char* KEY_ENABLE = "Enable"; + +ConfigOpr::ConfigOpr() +{ + std::string home = get_home(); + fs::path config_dir = fs::path(home).append(".config").append("FTPTrans"); + auto ini_path = fs::path(config_dir).append("config.ini"); + std::snprintf(ini_path_, sizeof(ini_path_), "%s", ini_path.string().c_str()); + + if (!fs::exists(config_dir)) { + fs::create_directories(config_dir); + } + if (!fs::exists(ini_path_)) { + generate_default(); + return; + } +} + +void ConfigOpr::push(const ItemContent& item) +{ + check_open(); + + std::string new_name(HEAD_ITEM); + new_name += std::to_string(item.id); + + ini_.SetValue(new_name.c_str(), KEY_SOURCE, item.source.c_str()); + ini_.SetValue(new_name.c_str(), KEY_DES, item.des.c_str()); + ini_.SetBoolValue(new_name.c_str(), KEY_ENABLE, true); + + save(); +} + +bool ConfigOpr::update(int id, const ItemContent* ptem, bool enable) +{ + check_open(); + + long cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + if (id > cnt) { + return false; + } + + std::string new_name(HEAD_ITEM); + new_name += std::to_string(id); + + if (!enable) { + bool ret = ini_.SetBoolValue(new_name.c_str(), KEY_ENABLE, false) == SI_UPDATED; + assert(ret); + save(); + return true; + } + + if (!ptem) { + return false; + } + + ini_.SetValue(new_name.c_str(), KEY_SOURCE, ptem->source.c_str()); + ini_.SetValue(new_name.c_str(), KEY_DES, ptem->des.c_str()); + ini_.SetBoolValue(new_name.c_str(), KEY_ENABLE, true); + + save(); + + return true; +} + +long ConfigOpr::get_count() +{ + check_open(); + + long cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + return cnt; +} + +bool ConfigOpr::get_content(int id, ItemContent& item) +{ + check_open(); + + long cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + if (id > cnt) { + return false; + } + std::string new_name(HEAD_ITEM); + new_name += std::to_string(id); + + item.enable = ini_.GetBoolValue(new_name.c_str(), KEY_ENABLE); + item.des = ini_.GetValue(new_name.c_str(), KEY_DES); + item.source = ini_.GetValue(new_name.c_str(), KEY_SOURCE); + item.id = id; + return true; +} + +bool ConfigOpr::get_base(ItemBase& base) +{ + check_open(); + base.cnt = ini_.GetLongValue(HEAD_BASIC, KEY_ITEMCNT); + base.ip.append(ini_.GetValue(HEAD_BASIC, KEY_IP)); + base.port = std::stoi(ini_.GetValue(HEAD_BASIC, KEY_PORT)); + base.pwd.append(ini_.GetValue(HEAD_BASIC, KEY_PWD)); + base.user.append(ini_.GetValue(HEAD_BASIC, KEY_USERNAME)); + return true; +} + +bool ConfigOpr::set_base(const ItemBase& base) +{ + check_open(); + ini_.SetLongValue(HEAD_BASIC, KEY_ITEMCNT, base.cnt); + ini_.SetValue(HEAD_BASIC, KEY_IP, base.ip.c_str()); + ini_.SetLongValue(HEAD_BASIC, KEY_PORT, base.port); + ini_.SetValue(HEAD_BASIC, KEY_USERNAME, base.user.c_str()); + ini_.SetValue(HEAD_BASIC, KEY_PWD, base.pwd.c_str()); + save(); + return true; +} + +std::string ConfigOpr::get_home() +{ +#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) + return std::getenv("USERPROFILE"); +#else + const char* homedir = getenv("HOME"); + if (homedir) { + return std::string(homedir); + } + return ""; +#endif +} + +void ConfigOpr::generate_default() +{ + ini_.SetLongValue(HEAD_BASIC, KEY_ITEMCNT, 0); + ini_.SetValue(HEAD_BASIC, KEY_IP, "192.168.0.9"); + ini_.SetLongValue(HEAD_BASIC, KEY_PORT, 21); + ini_.SetValue(HEAD_BASIC, KEY_USERNAME, "lebo"); + ini_.SetValue(HEAD_BASIC, KEY_PWD, "123456"); + ini_.SaveFile(ini_path_); +} + +void ConfigOpr::check_open() +{ + if (ini_.IsEmpty()) { + bool ret = (ini_.LoadFile(ini_path_) == SI_OK); + assert(ret); + } +} + +void ConfigOpr::save() +{ + bool ret = ini_.SaveFile(ini_path_) == SI_OK; + assert(ret); +} diff --git a/src/ConfigOpr.h b/src/ConfigOpr.h new file mode 100644 index 0000000..2a67b47 --- /dev/null +++ b/src/ConfigOpr.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +namespace fs = std::filesystem; + +struct ItemBase { + std::string ip{}; + int port{}; + long cnt{}; + std::string user{}; + std::string pwd{}; +}; + +struct ItemContent +{ + int id{}; + bool enable{ false }; + std::string source{}; + std::string des{}; + std::string des_full{}; +}; + +class ConfigOpr +{ +public: + ConfigOpr(); + ~ConfigOpr() = default; + +public: + void push(const ItemContent& item); + bool update(int id, const ItemContent* ptem, bool enable = true); + long get_count(); + bool get_content(int id, ItemContent& item); + bool get_base(ItemBase& base); + bool set_base(const ItemBase& base); + +private: + std::string get_home(); + void generate_default(); + void check_open(); + void save(); + +private: + char ini_path_[512]{}; + CSimpleIniA ini_{}; +}; + diff --git a/src/FTPTrans.cpp b/src/FTPTrans.cpp new file mode 100644 index 0000000..5bdb817 --- /dev/null +++ b/src/FTPTrans.cpp @@ -0,0 +1,232 @@ +#include "FTPTrans.h" +#include + +FTPTrans::FTPTrans(QWidget* parent) : QWidget(parent) +{ + ui.setupUi(this); + + ini_opr_ = new ConfigOpr(); + + setWindowTitle("FTPTrans v1.0.2"); + + init(); + + connect(ui.btnSave, &QPushButton::clicked, this, [&]() { save(true); }); + connect(ui.btnAdd, &QPushButton::clicked, [&]() { handle_table_add(); }); + connect(ui.btnUpdate, &QPushButton::clicked, [&]() { Trans(); }); + connect(ui.btnDown, &QPushButton::clicked, [&]() { Trans(false); }); +} + +void FTPTrans::save(bool is_notify) +{ + ini_base_.ip = ui.edIP->text().toStdString(); + ini_base_.port = ui.edPort->text().toInt(); + ini_base_.pwd = ui.edPwd->text().toStdString(); + ini_base_.user = ui.edUserName->text().toStdString(); + ini_base_.cnt = ui.tableWidget->rowCount(); + + ini_opr_->set_base(ini_base_); + + for (int i = 0; i < ini_base_.cnt; ++i) { + ItemContent content; + content.id = ui.tableWidget->item(i, 0)->text().toInt(); + content.source.append(ui.tableWidget->item(i, 1)->text().toLocal8Bit()); + content.des.append(ui.tableWidget->item(i, 2)->text().toLocal8Bit()); + ini_opr_->update(content.id, &content); + } + + if (is_notify) { + QMessageBox::information(this, u8"提示", u8"已存储"); + } +} + +FTPTrans::~FTPTrans() +{ + delete ini_opr_; +} + +size_t readFunc(void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + return fread(ptr, size, nmemb, stream); +} + +size_t writeFunc(void* ptr, size_t size, size_t nmemb, FILE* stream) +{ + return fwrite(ptr, size, nmemb, stream); +} + +void FTPTrans::Trans(bool is_up) +{ + if (is_up) { + if (!is_ok(this, u8"确认上传同步吗?")) { + return; + } + } else { + if (!is_ok(this, u8"确认下载同步吗?")) { + return; + } + } + + CURL* curl = nullptr; + + QList selectedItems = ui.tableWidget->selectedItems(); + if (selectedItems.size() != 3) { + QMessageBox::information(this, u8"提示", u8"未有选中数据"); + return; + } + + std::string source(selectedItems[1]->text().toLocal8Bit()); + std::string des(selectedItems[2]->text().toLocal8Bit()); + std::string user(ui.edUserName->text().toStdString()); + std::string pwd(ui.edPwd->text().toStdString()); + + try { + curl_global_init(CURL_GLOBAL_ALL); + + std::uintmax_t file_size{}; + if (is_up) { + fs::path source_file(source); + if (!fs::exists(source_file)) { + QMessageBox::information(this, u8"提示", QString::fromStdString(u8"文件不存在:" + source_file.string())); + return; + } + file_size = fs::file_size(source_file); + } + + curl = curl_easy_init(); + if (curl == nullptr) { + QMessageBox::information(this, u8"提示", u8"curl_easy_init 初始化失败"); + return; + } + + FILE* fd = nullptr; + if (is_up) { + fd = fopen(source.c_str(), "rb"); + } else { + fd = fopen(source.c_str(), "wb"); + } + + if (!fd) { + QMessageBox::information(this, u8"提示", QString::fromStdString(u8"文件打开失败:" + source)); + return; + } + + if (is_up) { + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + } + + curl_easy_setopt(curl, CURLOPT_URL, des.c_str()); + curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); + curl_easy_setopt(curl, CURLOPT_PASSWORD, pwd.c_str()); + + if (is_up) { + curl_easy_setopt(curl, CURLOPT_READFUNCTION, readFunc); + curl_easy_setopt(curl, CURLOPT_READDATA, fd); + } else { + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fd); + } + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + if (is_up) { + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, file_size); + } + + if (10) { + curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, 10); + } + + CURLcode r = curl_easy_perform(curl); + fclose(fd); + + if (r != CURLE_OK) { + QMessageBox::information(this, u8"错误提示", QString::fromLocal8Bit(curl_easy_strerror(r))); + return; + } + } catch (...) { + QMessageBox::information(this, u8"异常", u8"产生了异常"); + return; + } + + if (curl) { + curl_easy_cleanup(curl); + } + curl_global_cleanup(); + save(false); + QMessageBox::information(this, u8"提示", u8"完成"); +} + +void FTPTrans::init() +{ + ini_opr_->get_base(ini_base_); + ui.edIP->setText(QString::fromStdString(ini_base_.ip)); + ui.edPort->setText(QString::number(ini_base_.port)); + ui.edPwd->setText(QString::fromStdString(ini_base_.pwd)); + ui.edUserName->setText(QString::fromStdString(ini_base_.user)); + + QStringList headers; + headers << u8"标识号" << u8"源位置(本地)" << u8"目的位置(FTP位置)"; + ui.tableWidget->setColumnCount(headers.size()); + ui.tableWidget->setHorizontalHeaderLabels(headers); + + ui.tableWidget->setColumnWidth(0, 80); + ui.tableWidget->setColumnWidth(1, 450); + ui.tableWidget->horizontalHeader()->setStretchLastSection(true); + ui.tableWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); + ui.tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + ui.tableWidget->verticalHeader()->setVisible(false); + + ui.btnAdd->setMinimumHeight(35); + ui.btnDown->setMinimumHeight(35); + ui.btnSave->setMinimumHeight(35); + ui.btnUpdate->setMinimumHeight(35); + + handle_table_read(); +} + +void FTPTrans::handle_table_read() +{ + int cnt = ini_opr_->get_count(); + for (int i = 1; i < cnt + 1; ++i) { + ItemContent content; + ini_opr_->get_content(i, content); + int rowCnt = ui.tableWidget->rowCount(); + ui.tableWidget->insertRow(rowCnt); + QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(content.id)); + item0->setFlags(item0->flags() & ~Qt::ItemIsEditable); + ui.tableWidget->setItem(rowCnt, 0, item0); + QTableWidgetItem* item1 = new QTableWidgetItem(QString::fromLocal8Bit(content.source.c_str())); + ui.tableWidget->setItem(rowCnt, 1, item1); + QTableWidgetItem* item2 = new QTableWidgetItem(QString::fromLocal8Bit(content.des.c_str())); + ui.tableWidget->setItem(rowCnt, 2, item2); + } +} + +void FTPTrans::handle_table_add() +{ + int rowCnt = ui.tableWidget->rowCount(); + ui.tableWidget->insertRow(rowCnt); + QTableWidgetItem* item0 = new QTableWidgetItem(QString::number(rowCnt + 1)); + item0->setFlags(item0->flags() & ~Qt::ItemIsEditable); + ui.tableWidget->setItem(rowCnt, 0, item0); + QTableWidgetItem* item1 = new QTableWidgetItem(""); + ui.tableWidget->setItem(rowCnt, 1, item1); + QTableWidgetItem* item2 = new QTableWidgetItem(""); + ui.tableWidget->setItem(rowCnt, 2, item2); +} + +bool FTPTrans::is_ok(QWidget* parent, const QString& content) +{ + QMessageBox questionBox(parent); + questionBox.setText(content); + questionBox.setWindowTitle(u8"提示"); + questionBox.setIcon(QMessageBox::Question); + questionBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + int result = questionBox.exec(); + if (result != QMessageBox::Yes) { + return false; + } else { + return true; + } +} diff --git a/src/FTPTrans.h b/src/FTPTrans.h new file mode 100644 index 0000000..0667d5e --- /dev/null +++ b/src/FTPTrans.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "ui_FTPTrans.h" +#include "ConfigOpr.h" +#include + +class FTPTrans : public QWidget +{ + Q_OBJECT + +public: + FTPTrans(QWidget *parent = nullptr); + ~FTPTrans(); + +public: + void Trans(bool is_up = true); + void init(); + void handle_table_read(); + void handle_table_add(); + void save(bool is_notify = false); + +private: + bool is_ok(QWidget* parent, const QString& content); +private: + Ui::FTPTransClass ui; + ConfigOpr* ini_opr_{}; + ItemBase ini_base_{}; +}; diff --git a/src/FTPTrans.ico b/src/FTPTrans.ico new file mode 100644 index 0000000000000000000000000000000000000000..1c4fb80d0527ef003399ff11bbcebdb162bf7725 GIT binary patch literal 370070 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 LC;>_!^%D610I=HW literal 0 HcmV?d00001 diff --git a/src/FTPTrans.qrc b/src/FTPTrans.qrc new file mode 100644 index 0000000..c62a9e9 --- /dev/null +++ b/src/FTPTrans.qrc @@ -0,0 +1,4 @@ + + + + diff --git a/src/FTPTrans.rc b/src/FTPTrans.rc new file mode 100644 index 0000000..24a265a --- /dev/null +++ b/src/FTPTrans.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "FTPTrans.ico" diff --git a/src/FTPTrans.ui b/src/FTPTrans.ui new file mode 100644 index 0000000..af21ecd --- /dev/null +++ b/src/FTPTrans.ui @@ -0,0 +1,156 @@ + + + FTPTransClass + + + + 0 + 0 + 1461 + 605 + + + + FTPTrans + + + + + + FTP基本信息 + + + + + + + + + 用户名: + + + + + + + IP: + + + + + + + 端口: + + + + + + + + + + 密码: + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 文件传输(远端暂不支持中文路径) + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 添加 + + + + + + + 上传同步 + + + + + + + 下载同步 + + + + + + + 保存 + + + + + + + + + + + + + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..84db3dc --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,14 @@ +#include "FTPTrans.h" +#include + +int main(int argc, char *argv[]) +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif + QApplication a(argc, argv); + a.setStyle("windows xp"); + FTPTrans w; + w.show(); + return a.exec(); +}