3 Commits

Author SHA1 Message Date
Бычков Анлрей
e85b11a233 PIMap via pipair, fix tests 2022-05-26 18:07:44 +03:00
Бычков Анлрей
831adf3fc9 some new tests 2022-05-25 18:52:19 +03:00
Бычков Анлрей
a18f461ce3 pimap tests 2022-05-24 18:40:06 +03:00
479 changed files with 33340 additions and 59730 deletions

View File

@@ -1,224 +0,0 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: CurrentLine
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- piForeach
- piForeachC
- piForeachR
- piForeachRC
- piForeachCR
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentExternBlock: NoIndent
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: Wrapped
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
MacroBlockBegin: "PRIVATE_DEFINITION_START|STATIC_INITIALIZER_BEGIN"
MacroBlockEnd: "PRIVATE_DEFINITION_END|STATIC_INITIALIZER_END"
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Middle
PPIndentWidth: 2
ReferenceAlignment: Middle
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatementsExceptControlMacros
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: false
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: false
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Both
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: After
Standard: c++11
StatementAttributeLikeMacros:
- Q_EMIT
- PIMETA
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
- PRIVATE_DECLARATION
- NO_COPY_CLASS
- FOREVER_WAIT
- WAIT_FOREVER
TabWidth: 4
UseCRLF: false
UseTab: AlignWithSpaces
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
- PIMETA
...

View File

@@ -1,6 +0,0 @@
root = true
[*.{h,c,cpp}]
charset = utf-8
indent_style = tab
tab_width = 4

4
.gitignore vendored
View File

@@ -3,6 +3,4 @@
/doc/rtf /doc/rtf
_unsused _unsused
CMakeLists.txt.user* CMakeLists.txt.user*
/include /include
/release
/build*

View File

@@ -1,160 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#ifndef BLAKE2_IMPL_H
#define BLAKE2_IMPL_H
#include <stdint.h>
#include <string.h>
#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#if defined(_MSC_VER)
#define BLAKE2_INLINE __inline
#elif defined(__GNUC__)
#define BLAKE2_INLINE __inline__
#else
#define BLAKE2_INLINE
#endif
#else
#define BLAKE2_INLINE inline
#endif
static BLAKE2_INLINE uint32_t load32( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8) |
(( uint32_t )( p[2] ) << 16) |
(( uint32_t )( p[3] ) << 24) ;
#endif
}
static BLAKE2_INLINE uint64_t load64( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint64_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) |
(( uint64_t )( p[6] ) << 48) |
(( uint64_t )( p[7] ) << 56) ;
#endif
}
static BLAKE2_INLINE uint16_t load16( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint16_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return ( uint16_t )((( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8));
#endif
}
static BLAKE2_INLINE void store16( void *dst, uint16_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static BLAKE2_INLINE void store32( void *dst, uint32_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
#endif
}
static BLAKE2_INLINE void store64( void *dst, uint64_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
p[6] = (uint8_t)(w >> 48);
p[7] = (uint8_t)(w >> 56);
#endif
}
static BLAKE2_INLINE uint64_t load48( const void *src )
{
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) ;
}
static BLAKE2_INLINE void store48( void *dst, uint64_t w )
{
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
}
static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
}
static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
}
/* prevents compiler optimizing out memset() */
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
{
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);
}
#endif

View File

@@ -1,195 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#ifndef BLAKE2_H
#define BLAKE2_H
#include <stddef.h>
#include <stdint.h>
#if defined(_MSC_VER)
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
#else
#define BLAKE2_PACKED(x) x __attribute__((packed))
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32,
BLAKE2S_KEYBYTES = 32,
BLAKE2S_SALTBYTES = 8,
BLAKE2S_PERSONALBYTES = 8
};
enum blake2b_constant
{
BLAKE2B_BLOCKBYTES = 128,
BLAKE2B_OUTBYTES = 64,
BLAKE2B_KEYBYTES = 64,
BLAKE2B_SALTBYTES = 16,
BLAKE2B_PERSONALBYTES = 16
};
typedef struct blake2s_state__
{
uint32_t h[8];
uint32_t t[2];
uint32_t f[2];
uint8_t buf[BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2s_state;
typedef struct blake2b_state__
{
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2b_state;
typedef struct blake2sp_state__
{
blake2s_state S[8][1];
blake2s_state R[1];
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2sp_state;
typedef struct blake2bp_state__
{
blake2b_state S[4][1];
blake2b_state R[1];
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2bp_state;
BLAKE2_PACKED(struct blake2s_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint16_t xof_length; /* 14 */
uint8_t node_depth; /* 15 */
uint8_t inner_length; /* 16 */
/* uint8_t reserved[0]; */
uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
});
typedef struct blake2s_param__ blake2s_param;
BLAKE2_PACKED(struct blake2b_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint32_t xof_length; /* 16 */
uint8_t node_depth; /* 17 */
uint8_t inner_length; /* 18 */
uint8_t reserved[14]; /* 32 */
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
});
typedef struct blake2b_param__ blake2b_param;
typedef struct blake2xs_state__
{
blake2s_state S[1];
blake2s_param P[1];
} blake2xs_state;
typedef struct blake2xb_state__
{
blake2b_state S[1];
blake2b_param P[1];
} blake2xb_state;
/* Padded structs result in a compile-time error */
enum {
BLAKE2_DUMMY_1 = 1/(int)(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),
BLAKE2_DUMMY_2 = 1/(int)(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)
};
/* Streaming API */
int blake2s_init( blake2s_state *S, size_t outlen );
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
int blake2s_update( blake2s_state *S, const void *in, size_t inlen );
int blake2s_final( blake2s_state *S, void *out, size_t outlen );
int blake2b_init( blake2b_state *S, size_t outlen );
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
int blake2b_update( blake2b_state *S, const void *in, size_t inlen );
int blake2b_final( blake2b_state *S, void *out, size_t outlen );
int blake2sp_init( blake2sp_state *S, size_t outlen );
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );
int blake2bp_init( blake2bp_state *S, size_t outlen );
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );
/* Variable output length API */
int blake2xs_init( blake2xs_state *S, const size_t outlen );
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);
int blake2xb_init( blake2xb_state *S, const size_t outlen );
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );
int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);
/* Simple API */
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
/* This is simply an alias for blake2b */
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
#if defined(__cplusplus)
}
#endif
#endif

View File

@@ -1,379 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint64_t blake2b_IV[8] =
{
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
static const uint8_t blake2b_sigma[12][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
};
static void blake2b_set_lastnode( blake2b_state *S )
{
S->f[1] = (uint64_t)-1;
}
/* Some helper functions, not necessarily useful */
static int blake2b_is_lastblock( const blake2b_state *S )
{
return S->f[0] != 0;
}
static void blake2b_set_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_set_lastnode( S );
S->f[0] = (uint64_t)-1;
}
static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
static void blake2b_init0( blake2b_state *S )
{
size_t i;
memset( S, 0, sizeof( blake2b_state ) );
for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
}
/* init xors IV with input parameter block */
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
{
const uint8_t *p = ( const uint8_t * )( P );
size_t i;
blake2b_init0( S );
/* IV XOR ParamBlock */
for( i = 0; i < 8; ++i )
S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
S->outlen = P->digest_length;
return 0;
}
int blake2b_init( blake2b_state *S, size_t outlen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2b_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2b_sigma[r][2*i+0]]; \
d = rotr64(d ^ a, 32); \
c = c + d; \
b = rotr64(b ^ c, 24); \
a = a + b + m[blake2b_sigma[r][2*i+1]]; \
d = rotr64(d ^ a, 16); \
c = c + d; \
b = rotr64(b ^ c, 63); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
{
uint64_t m[16];
uint64_t v[16];
size_t i;
for( i = 0; i < 16; ++i ) {
m[i] = load64( block + i * sizeof( m[i] ) );
}
for( i = 0; i < 8; ++i ) {
v[i] = S->h[i];
}
v[ 8] = blake2b_IV[0];
v[ 9] = blake2b_IV[1];
v[10] = blake2b_IV[2];
v[11] = blake2b_IV[3];
v[12] = blake2b_IV[4] ^ S->t[0];
v[13] = blake2b_IV[5] ^ S->t[1];
v[14] = blake2b_IV[6] ^ S->f[0];
v[15] = blake2b_IV[7] ^ S->f[1];
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
ROUND( 10 );
ROUND( 11 );
for( i = 0; i < 8; ++i ) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
}
#undef G
#undef ROUND
int blake2b_update( blake2b_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
if( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = BLAKE2B_BLOCKBYTES - left;
if( inlen > fill )
{
S->buflen = 0;
memcpy( S->buf + left, in, fill ); /* Fill buffer */
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf ); /* Compress */
in += fill; inlen -= fill;
while(inlen > BLAKE2B_BLOCKBYTES) {
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
blake2b_compress( S, in );
in += BLAKE2B_BLOCKBYTES;
inlen -= BLAKE2B_BLOCKBYTES;
}
}
memcpy( S->buf + S->buflen, in, inlen );
S->buflen += inlen;
}
return 0;
}
int blake2b_final( blake2b_state *S, void *out, size_t outlen )
{
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
size_t i;
if( out == NULL || outlen < S->outlen )
return -1;
if( blake2b_is_lastblock( S ) )
return -1;
blake2b_increment_counter( S, S->buflen );
blake2b_set_lastblock( S );
memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
blake2b_compress( S, S->buf );
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, S->outlen );
secure_zero_memory(buffer, sizeof(buffer));
return 0;
}
/* inlen, at least, should be uint64_t. Others can be size_t. */
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
blake2b_state S[1];
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if( NULL == key && keylen > 0 ) return -1;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( keylen > BLAKE2B_KEYBYTES ) return -1;
if( keylen > 0 )
{
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2b_init( S, outlen ) < 0 ) return -1;
}
blake2b_update( S, ( const uint8_t * )in, inlen );
blake2b_final( S, out, outlen );
return 0;
}
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) {
return blake2b(out, outlen, in, inlen, key, keylen);
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 );
}
#endif
#if defined(BLAKE2B_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2b_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2b_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -1,359 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 4
/*
blake2b_init_param defaults to setting the expecting output length
from the digest_length parameter block field.
In some cases, however, we do not want this, as the output length
of these instances is given by inner_length instead.
*/
static int blake2bp_init_leaf_param( blake2b_state *S, const blake2b_param *P )
{
int err = blake2b_init_param(S, P);
S->outlen = P->inner_length;
return err;
}
static int blake2bp_init_leaf( blake2b_state *S, size_t outlen, size_t keylen, uint64_t offset )
{
blake2b_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, offset );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = BLAKE2B_OUTBYTES;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2bp_init_leaf_param( S, P );
}
static int blake2bp_init_root( blake2b_state *S, size_t outlen, size_t keylen )
{
blake2b_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 1;
P->inner_length = BLAKE2B_OUTBYTES;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2bp_init( blake2bp_state *S, size_t outlen )
{
size_t i;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2bp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen )
{
size_t i;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2bp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2bp_update( blake2bp_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
size_t i;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S->S[i], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
size_t i;
if(out == NULL || outlen < S->outlen) {
return -1;
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2B_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2B_BLOCKBYTES;
if( left > BLAKE2B_BLOCKBYTES ) left = BLAKE2B_BLOCKBYTES;
blake2b_update( S->S[i], S->buf + i * BLAKE2B_BLOCKBYTES, left );
}
blake2b_final( S->S[i], hash[i], BLAKE2B_OUTBYTES );
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S->R, hash[i], BLAKE2B_OUTBYTES );
return blake2b_final( S->R, out, S->outlen );
}
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2B_OUTBYTES];
blake2b_state S[PARALLELISM_DEGREE][1];
blake2b_state FS[1];
size_t i;
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if( NULL == key && keylen > 0 ) return -1;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( keylen > BLAKE2B_KEYBYTES ) return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2bp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
if( keylen > 0 )
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( S[i], block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2B_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES )
{
blake2b_update( S[i], in__, BLAKE2B_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2B_BLOCKBYTES;
}
if( inlen__ > i * BLAKE2B_BLOCKBYTES )
{
const size_t left = inlen__ - i * BLAKE2B_BLOCKBYTES;
const size_t len = left <= BLAKE2B_BLOCKBYTES ? left : BLAKE2B_BLOCKBYTES;
blake2b_update( S[i], in__, len );
}
blake2b_final( S[i], hash[i], BLAKE2B_OUTBYTES );
}
if( blake2bp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1; /* Mark as last node */
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2b_update( FS, hash[i], BLAKE2B_OUTBYTES );
return blake2b_final( FS, out, outlen );;
}
#if defined(BLAKE2BP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2bp( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2B_OUTBYTES];
blake2bp_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2bp_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2bp_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2bp_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2bp_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2bp_keyed_kat[i], BLAKE2B_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -1,367 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint32_t blake2s_IV[8] =
{
0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
};
static const uint8_t blake2s_sigma[10][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
};
static void blake2s_set_lastnode( blake2s_state *S )
{
S->f[1] = (uint32_t)-1;
}
/* Some helper functions, not necessarily useful */
static int blake2s_is_lastblock( const blake2s_state *S )
{
return S->f[0] != 0;
}
static void blake2s_set_lastblock( blake2s_state *S )
{
if( S->last_node ) blake2s_set_lastnode( S );
S->f[0] = (uint32_t)-1;
}
static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
static void blake2s_init0( blake2s_state *S )
{
size_t i;
memset( S, 0, sizeof( blake2s_state ) );
for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i];
}
/* init2 xors IV with input parameter block */
int blake2s_init_param( blake2s_state *S, const blake2s_param *P )
{
const unsigned char *p = ( const unsigned char * )( P );
size_t i;
blake2s_init0( S );
/* IV XOR ParamBlock */
for( i = 0; i < 8; ++i )
S->h[i] ^= load32( &p[i * 4] );
S->outlen = P->digest_length;
return 0;
}
/* Sequential blake2s initialization */
int blake2s_init( blake2s_state *S, size_t outlen )
{
blake2s_param P[1];
/* Move interval verification here? */
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen )
{
blake2s_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
/* memset(P->reserved, 0, sizeof(P->reserved) ); */
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2s_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
blake2s_update( S, block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2s_sigma[r][2*i+0]]; \
d = rotr32(d ^ a, 16); \
c = c + d; \
b = rotr32(b ^ c, 12); \
a = a + b + m[blake2s_sigma[r][2*i+1]]; \
d = rotr32(d ^ a, 8); \
c = c + d; \
b = rotr32(b ^ c, 7); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] )
{
uint32_t m[16];
uint32_t v[16];
size_t i;
for( i = 0; i < 16; ++i ) {
m[i] = load32( in + i * sizeof( m[i] ) );
}
for( i = 0; i < 8; ++i ) {
v[i] = S->h[i];
}
v[ 8] = blake2s_IV[0];
v[ 9] = blake2s_IV[1];
v[10] = blake2s_IV[2];
v[11] = blake2s_IV[3];
v[12] = S->t[0] ^ blake2s_IV[4];
v[13] = S->t[1] ^ blake2s_IV[5];
v[14] = S->f[0] ^ blake2s_IV[6];
v[15] = S->f[1] ^ blake2s_IV[7];
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
for( i = 0; i < 8; ++i ) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
}
#undef G
#undef ROUND
int blake2s_update( blake2s_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
if( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = BLAKE2S_BLOCKBYTES - left;
if( inlen > fill )
{
S->buflen = 0;
memcpy( S->buf + left, in, fill ); /* Fill buffer */
blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
blake2s_compress( S, S->buf ); /* Compress */
in += fill; inlen -= fill;
while(inlen > BLAKE2S_BLOCKBYTES) {
blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
blake2s_compress( S, in );
in += BLAKE2S_BLOCKBYTES;
inlen -= BLAKE2S_BLOCKBYTES;
}
}
memcpy( S->buf + S->buflen, in, inlen );
S->buflen += inlen;
}
return 0;
}
int blake2s_final( blake2s_state *S, void *out, size_t outlen )
{
uint8_t buffer[BLAKE2S_OUTBYTES] = {0};
size_t i;
if( out == NULL || outlen < S->outlen )
return -1;
if( blake2s_is_lastblock( S ) )
return -1;
blake2s_increment_counter( S, ( uint32_t )S->buflen );
blake2s_set_lastblock( S );
memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
blake2s_compress( S, S->buf );
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store32( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, outlen );
secure_zero_memory(buffer, sizeof(buffer));
return 0;
}
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
blake2s_state S[1];
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key && keylen > 0) return -1;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( keylen > BLAKE2S_KEYBYTES ) return -1;
if( keylen > 0 )
{
if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2s_init( S, outlen ) < 0 ) return -1;
}
blake2s_update( S, ( const uint8_t * )in, inlen );
blake2s_final( S, out, outlen );
return 0;
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2s( out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0 );
}
#endif
#if defined(BLAKE2S_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2s( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2S_OUTBYTES];
blake2s_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2s_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2s_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -1,359 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#if defined(_OPENMP)
#include <omp.h>
#endif
#include "blake2.h"
#include "blake2-impl.h"
#define PARALLELISM_DEGREE 8
/*
blake2sp_init_param defaults to setting the expecting output length
from the digest_length parameter block field.
In some cases, however, we do not want this, as the output length
of these instances is given by inner_length instead.
*/
static int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P )
{
int err = blake2s_init_param(S, P);
S->outlen = P->inner_length;
return err;
}
static int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint64_t offset )
{
blake2s_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, offset );
store16( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = BLAKE2S_OUTBYTES;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2sp_init_leaf_param( S, P );
}
static int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen )
{
blake2s_param P[1];
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = PARALLELISM_DEGREE;
P->depth = 2;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store16( &P->xof_length, 0 );
P->node_depth = 1;
P->inner_length = BLAKE2S_OUTBYTES;
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2s_init_param( S, P );
}
int blake2sp_init( blake2sp_state *S, size_t outlen )
{
size_t i;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, 0, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
return 0;
}
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen )
{
size_t i;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
memset( S->buf, 0, sizeof( S->buf ) );
S->buflen = 0;
S->outlen = outlen;
if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )
return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S->S[i], outlen, keylen, i ) < 0 ) return -1;
S->R->last_node = 1;
S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
int blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
size_t left = S->buflen;
size_t fill = sizeof( S->buf ) - left;
size_t i;
if( left && inlen >= fill )
{
memcpy( S->buf + left, in, fill );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
in += fill;
inlen -= fill;
left = 0;
}
#if defined(_OPENMP)
#pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
}
in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
if( inlen > 0 )
memcpy( S->buf + left, in, inlen );
S->buflen = left + inlen;
return 0;
}
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
size_t i;
if(out == NULL || outlen < S->outlen) {
return -1;
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
{
if( S->buflen > i * BLAKE2S_BLOCKBYTES )
{
size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
}
blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
}
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
return blake2s_final( S->R, out, S->outlen );
}
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
blake2s_state S[PARALLELISM_DEGREE][1];
blake2s_state FS[1];
size_t i;
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if ( NULL == key && keylen > 0) return -1;
if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
if( keylen > BLAKE2S_KEYBYTES ) return -1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
if( blake2sp_init_leaf( S[i], outlen, keylen, i ) < 0 ) return -1;
S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
if( keylen > 0 )
{
uint8_t block[BLAKE2S_BLOCKBYTES];
memset( block, 0, BLAKE2S_BLOCKBYTES );
memcpy( block, key, keylen );
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
}
#if defined(_OPENMP)
#pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
#else
for( i = 0; i < PARALLELISM_DEGREE; ++i )
#endif
{
#if defined(_OPENMP)
size_t i = omp_get_thread_num();
#endif
size_t inlen__ = inlen;
const unsigned char *in__ = ( const unsigned char * )in;
in__ += i * BLAKE2S_BLOCKBYTES;
while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
{
blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES );
in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
}
if( inlen__ > i * BLAKE2S_BLOCKBYTES )
{
const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES;
const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
blake2s_update( S[i], in__, len );
}
blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES );
}
if( blake2sp_init_root( FS, outlen, keylen ) < 0 )
return -1;
FS->last_node = 1;
for( i = 0; i < PARALLELISM_DEGREE; ++i )
blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
return blake2s_final( FS, out, outlen );
}
#if defined(BLAKE2SP_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2S_OUTBYTES];
blake2sp_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2sp_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2sp_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -1,241 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2016, JP Aumasson <jeanphilippe.aumasson@gmail.com>.
Copyright 2016, Samuel Neves <sneves@dei.uc.pt>.
You may use this under the terms of the CC0, the OpenSSL Licence, or
the Apache Public License 2.0, at your option. The terms of these
licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
int blake2xb_init( blake2xb_state *S, const size_t outlen ) {
return blake2xb_init_key(S, outlen, NULL, 0);
}
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen)
{
if ( outlen == 0 || outlen > 0xFFFFFFFFUL ) {
return -1;
}
if (NULL != key && keylen > BLAKE2B_KEYBYTES) {
return -1;
}
if (NULL == key && keylen > 0) {
return -1;
}
/* Initialize parameter block */
S->P->digest_length = BLAKE2B_OUTBYTES;
S->P->key_length = keylen;
S->P->fanout = 1;
S->P->depth = 1;
store32( &S->P->leaf_length, 0 );
store32( &S->P->node_offset, 0 );
store32( &S->P->xof_length, outlen );
S->P->node_depth = 0;
S->P->inner_length = 0;
memset( S->P->reserved, 0, sizeof( S->P->reserved ) );
memset( S->P->salt, 0, sizeof( S->P->salt ) );
memset( S->P->personal, 0, sizeof( S->P->personal ) );
if( blake2b_init_param( S->S, S->P ) < 0 ) {
return -1;
}
if (keylen > 0) {
uint8_t block[BLAKE2B_BLOCKBYTES];
memset(block, 0, BLAKE2B_BLOCKBYTES);
memcpy(block, key, keylen);
blake2b_update(S->S, block, BLAKE2B_BLOCKBYTES);
secure_zero_memory(block, BLAKE2B_BLOCKBYTES);
}
return 0;
}
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen ) {
return blake2b_update( S->S, in, inlen );
}
int blake2xb_final( blake2xb_state *S, void *out, size_t outlen) {
blake2b_state C[1];
blake2b_param P[1];
uint32_t xof_length = load32(&S->P->xof_length);
uint8_t root[BLAKE2B_BLOCKBYTES];
size_t i;
if (NULL == out) {
return -1;
}
/* outlen must match the output size defined in xof_length, */
/* unless it was -1, in which case anything goes except 0. */
if(xof_length == 0xFFFFFFFFUL) {
if(outlen == 0) {
return -1;
}
} else {
if(outlen != xof_length) {
return -1;
}
}
/* Finalize the root hash */
if (blake2b_final(S->S, root, BLAKE2B_OUTBYTES) < 0) {
return -1;
}
/* Set common block structure values */
/* Copy values from parent instance, and only change the ones below */
memcpy(P, S->P, sizeof(blake2b_param));
P->key_length = 0;
P->fanout = 0;
P->depth = 0;
store32(&P->leaf_length, BLAKE2B_OUTBYTES);
P->inner_length = BLAKE2B_OUTBYTES;
P->node_depth = 0;
for (i = 0; outlen > 0; ++i) {
const size_t block_size = (outlen < BLAKE2B_OUTBYTES) ? outlen : BLAKE2B_OUTBYTES;
/* Initialize state */
P->digest_length = block_size;
store32(&P->node_offset, i);
blake2b_init_param(C, P);
/* Process key if needed */
blake2b_update(C, root, BLAKE2B_OUTBYTES);
if (blake2b_final(C, (uint8_t *)out + i * BLAKE2B_OUTBYTES, block_size) < 0 ) {
return -1;
}
outlen -= block_size;
}
secure_zero_memory(root, sizeof(root));
secure_zero_memory(P, sizeof(P));
secure_zero_memory(C, sizeof(C));
/* Put blake2xb in an invalid state? cf. blake2s_is_lastblock */
return 0;
}
int blake2xb(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
{
blake2xb_state S[1];
/* Verify parameters */
if (NULL == in && inlen > 0)
return -1;
if (NULL == out)
return -1;
if (NULL == key && keylen > 0)
return -1;
if (keylen > BLAKE2B_KEYBYTES)
return -1;
if (outlen == 0)
return -1;
/* Initialize the root block structure */
if (blake2xb_init_key(S, outlen, key, keylen) < 0) {
return -1;
}
/* Absorb the input message */
blake2xb_update(S, in, inlen);
/* Compute the root node of the tree and the final hash using the counter construction */
return blake2xb_final(S, out, outlen);
}
#if defined(BLAKE2XB_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step, outlen;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) {
key[i] = ( uint8_t )i;
}
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) {
buf[i] = ( uint8_t )i;
}
/* Testing length of outputs rather than inputs */
/* (Test of input lengths mostly covered by blake2b tests) */
/* Test simple API */
for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen )
{
uint8_t hash[BLAKE2_KAT_LENGTH] = {0};
if( blake2xb( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2B_KEYBYTES ) < 0 ) {
goto fail;
}
if( 0 != memcmp( hash, blake2xb_keyed_kat[outlen-1], outlen ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) {
uint8_t hash[BLAKE2_KAT_LENGTH];
blake2xb_state S;
uint8_t * p = buf;
size_t mlen = BLAKE2_KAT_LENGTH;
int err = 0;
if( (err = blake2xb_init_key(&S, outlen, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2xb_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2xb_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2xb_final(&S, hash, outlen)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2xb_keyed_kat[outlen-1], outlen)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -1,239 +0,0 @@
/*
BLAKE2 reference source code package - reference C implementations
Copyright 2016, JP Aumasson <jeanphilippe.aumasson@gmail.com>.
Copyright 2016, Samuel Neves <sneves@dei.uc.pt>.
You may use this under the terms of the CC0, the OpenSSL Licence, or
the Apache Public License 2.0, at your option. The terms of these
licenses can be found at:
- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
int blake2xs_init( blake2xs_state *S, const size_t outlen ) {
return blake2xs_init_key(S, outlen, NULL, 0);
}
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen )
{
if ( outlen == 0 || outlen > 0xFFFFUL ) {
return -1;
}
if (NULL != key && keylen > BLAKE2S_KEYBYTES) {
return -1;
}
if (NULL == key && keylen > 0) {
return -1;
}
/* Initialize parameter block */
S->P->digest_length = BLAKE2S_OUTBYTES;
S->P->key_length = keylen;
S->P->fanout = 1;
S->P->depth = 1;
store32( &S->P->leaf_length, 0 );
store32( &S->P->node_offset, 0 );
store16( &S->P->xof_length, outlen );
S->P->node_depth = 0;
S->P->inner_length = 0;
memset( S->P->salt, 0, sizeof( S->P->salt ) );
memset( S->P->personal, 0, sizeof( S->P->personal ) );
if( blake2s_init_param( S->S, S->P ) < 0 ) {
return -1;
}
if (keylen > 0) {
uint8_t block[BLAKE2S_BLOCKBYTES];
memset(block, 0, BLAKE2S_BLOCKBYTES);
memcpy(block, key, keylen);
blake2s_update(S->S, block, BLAKE2S_BLOCKBYTES);
secure_zero_memory(block, BLAKE2S_BLOCKBYTES);
}
return 0;
}
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ) {
return blake2s_update( S->S, in, inlen );
}
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen) {
blake2s_state C[1];
blake2s_param P[1];
uint16_t xof_length = load16(&S->P->xof_length);
uint8_t root[BLAKE2S_BLOCKBYTES];
size_t i;
if (NULL == out) {
return -1;
}
/* outlen must match the output size defined in xof_length, */
/* unless it was -1, in which case anything goes except 0. */
if(xof_length == 0xFFFFUL) {
if(outlen == 0) {
return -1;
}
} else {
if(outlen != xof_length) {
return -1;
}
}
/* Finalize the root hash */
if (blake2s_final(S->S, root, BLAKE2S_OUTBYTES) < 0) {
return -1;
}
/* Set common block structure values */
/* Copy values from parent instance, and only change the ones below */
memcpy(P, S->P, sizeof(blake2s_param));
P->key_length = 0;
P->fanout = 0;
P->depth = 0;
store32(&P->leaf_length, BLAKE2S_OUTBYTES);
P->inner_length = BLAKE2S_OUTBYTES;
P->node_depth = 0;
for (i = 0; outlen > 0; ++i) {
const size_t block_size = (outlen < BLAKE2S_OUTBYTES) ? outlen : BLAKE2S_OUTBYTES;
/* Initialize state */
P->digest_length = block_size;
store32(&P->node_offset, i);
blake2s_init_param(C, P);
/* Process key if needed */
blake2s_update(C, root, BLAKE2S_OUTBYTES);
if (blake2s_final(C, (uint8_t *)out + i * BLAKE2S_OUTBYTES, block_size) < 0) {
return -1;
}
outlen -= block_size;
}
secure_zero_memory(root, sizeof(root));
secure_zero_memory(P, sizeof(P));
secure_zero_memory(C, sizeof(C));
/* Put blake2xs in an invalid state? cf. blake2s_is_lastblock */
return 0;
}
int blake2xs(void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen)
{
blake2xs_state S[1];
/* Verify parameters */
if (NULL == in && inlen > 0)
return -1;
if (NULL == out)
return -1;
if (NULL == key && keylen > 0)
return -1;
if (keylen > BLAKE2S_KEYBYTES)
return -1;
if (outlen == 0)
return -1;
/* Initialize the root block structure */
if (blake2xs_init_key(S, outlen, key, keylen) < 0) {
return -1;
}
/* Absorb the input message */
blake2xs_update(S, in, inlen);
/* Compute the root node of the tree and the final hash using the counter construction */
return blake2xs_final(S, out, outlen);
}
#if defined(BLAKE2XS_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2S_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step, outlen;
for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) {
key[i] = ( uint8_t )i;
}
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) {
buf[i] = ( uint8_t )i;
}
/* Testing length of outputs rather than inputs */
/* (Test of input lengths mostly covered by blake2s tests) */
/* Test simple API */
for( outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen )
{
uint8_t hash[BLAKE2_KAT_LENGTH] = {0};
if( blake2xs( hash, outlen, buf, BLAKE2_KAT_LENGTH, key, BLAKE2S_KEYBYTES ) < 0 ) {
goto fail;
}
if( 0 != memcmp( hash, blake2xs_keyed_kat[outlen-1], outlen ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
for (outlen = 1; outlen <= BLAKE2_KAT_LENGTH; ++outlen) {
uint8_t hash[BLAKE2_KAT_LENGTH];
blake2xs_state S;
uint8_t * p = buf;
size_t mlen = BLAKE2_KAT_LENGTH;
int err = 0;
if( (err = blake2xs_init_key(&S, outlen, key, BLAKE2S_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2xs_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2xs_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2xs_final(&S, hash, outlen)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2xs_keyed_kat[outlen-1], outlen)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@@ -5,7 +5,7 @@
*/ */
#define lapi_c #define lapi_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lcode_c #define lcode_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lctype_c #define lctype_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ldebug_c #define ldebug_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ldo_c #define ldo_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ldump_c #define ldump_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lfunc_c #define lfunc_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lgc_c #define lgc_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define llex_c #define llex_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lmem_c #define lmem_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lobject_c #define lobject_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lopcodes_c #define lopcodes_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lparser_c #define lparser_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lstate_c #define lstate_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lstring_c #define lstring_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ltable_c #define ltable_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define ltm_c #define ltm_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lundump_c #define lundump_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lvm_c #define lvm_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/ */
#define lzio_c #define lzio_c
#define LUA_CORE
#include "lprefix.h" #include "lprefix.h"

View File

@@ -1,26 +1,23 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0017 NEW) # need include() with .cmake
if (POLICY CMP0177) project(pip)
cmake_policy(SET CMP0177 OLD) set(pip_MAJOR 2)
endif() set(pip_MINOR 39)
project(PIP) set(pip_REVISION 0)
set(PIP_MAJOR 4) set(pip_SUFFIX )
set(PIP_MINOR 8) set(pip_COMPANY SHS)
set(PIP_REVISION 0) set(pip_DOMAIN org.SHS)
set(PIP_SUFFIX )
set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS)
set(GIT_CMAKE_DIR) set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT) if (NOT DEFINED SHSTKPROJECT)
set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cmake-download/CMakeLists.txt" file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cmake-download/CMakeLists.txt"
"# This file was generated by PIP CMake, don`t edit it! "# This file was generated by PIP CMake, don`t edit it!
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE) project(cmake-download NONE)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(cmake ExternalProject_Add(cmake
GIT_REPOSITORY https://git.shstk.ru/SHS/cmake.git GIT_REPOSITORY https://git.shs.tools/SHS/cmake.git
GIT_TAG \"origin/master\" GIT_TAG \"origin/master\"
GIT_CONFIG \"advice.detachedHead=false\" GIT_CONFIG \"advice.detachedHead=false\"
SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\" SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
@@ -45,7 +42,9 @@ ExternalProject_Add(cmake
set(GIT_CMAKE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake-src") set(GIT_CMAKE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake-src")
endif() endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") if ("x${CMAKE_MODULE_PATH}" STREQUAL "x")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
endif()
if (NOT "x${GIT_CMAKE_DIR}" STREQUAL "x") if (NOT "x${GIT_CMAKE_DIR}" STREQUAL "x")
list(APPEND CMAKE_MODULE_PATH "${GIT_CMAKE_DIR}") list(APPEND CMAKE_MODULE_PATH "${GIT_CMAKE_DIR}")
endif() endif()
@@ -54,8 +53,7 @@ include(CheckFunctionExists)
include(PIPMacros) include(PIPMacros)
include(SHSTKMacros) include(SHSTKMacros)
shstk_begin_project(PIP) shstk_begin_project(pip PIP)
set(PIP_VERSION "${PIP_VERSION}" CACHE STRING "")
set(_ICU_DEFAULT OFF) set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE)) if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
@@ -63,6 +61,7 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif() endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "") set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
# Options # Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT}) option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF) option(STD_IOSTREAM "Building with std iostream operators support" OFF)
@@ -73,13 +72,6 @@ set(PIP_UTILS 1)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
shstk_is_parent_exists(_pe)
if (_pe)
set(BUILDING_pip 1 PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
# Basic # Basic
set(PIP_MODULES) set(PIP_MODULES)
@@ -91,13 +83,10 @@ set(HDR_DIRS)
set(PIP_UTILS_LIST) set(PIP_UTILS_LIST)
set(PIP_TESTS_LIST) set(PIP_TESTS_LIST)
set(PIP_EXPORTS) set(PIP_EXPORTS)
set(PIP_3PL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rd")
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_client;http_server") set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;cloud;lua")
foreach(_m ${PIP_SRC_MODULES}) foreach(_m ${PIP_SRC_MODULES})
set(PIP_MSG_${_m} "no") set(PIP_MSG_${_m} "no")
string(TOUPPER "${_m}" _mu)
option(PIP_BUILD_${_mu} "Build \"${_m}\" module" ON)
endforeach() endforeach()
macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG) macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
@@ -119,10 +108,6 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
list(APPEND HDRS ${HS}) list(APPEND HDRS ${HS})
list(APPEND PHDRS ${PHS}) list(APPEND PHDRS ${PHS})
if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
else()
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${CPPS} ${HS} ${PHS})
endif()
set(_target "pip_${NAME}") set(_target "pip_${NAME}")
set(_libs "${LIBS}") set(_libs "${LIBS}")
if ("${NAME}" STREQUAL "main") if ("${NAME}" STREQUAL "main")
@@ -133,11 +118,11 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
string(TOUPPER "${_target}" DEF_NAME) string(TOUPPER "${_target}" DEF_NAME)
set(PIP_MSG_${NAME} "yes${MSG}") set(PIP_MSG_${NAME} "yes${MSG}")
import_version(${_target} PIP) import_version(${_target} pip)
set_deploy_property(${_target} ${PIP_LIB_TYPE} set_deploy_property(${_target} ${pip_LIB_TYPE}
LABEL "${LABEL}" LABEL "${LABEL}"
FULLNAME "${PIP_DOMAIN}.${_target}" FULLNAME "${pip_DOMAIN}.${_target}"
COMPANY "${PIP_COMPANY}" COMPANY "${pip_COMPANY}"
INFO "Platform-Independent Primitives") INFO "Platform-Independent Primitives")
make_rc(${_target} _RC) make_rc(${_target} _RC)
@@ -154,7 +139,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
pip_resources(CRES "${RES}") pip_resources(CRES "${RES}")
endif() endif()
add_definitions(-D${DEF_NAME}) add_definitions(-D${DEF_NAME})
add_library(${_target} ${PIP_LIB_TYPE} ${CPPS} ${CRES} ${_RC} ${HS} ${PHS}) add_library(${_target} ${pip_LIB_TYPE} ${CPPS} ${CRES} ${_RC})
target_include_directories(${_target} PUBLIC ${PIP_INCLUDES}) target_include_directories(${_target} PUBLIC ${PIP_INCLUDES})
if (NOT "x${RES}" STREQUAL "x") if (NOT "x${RES}" STREQUAL "x")
add_dependencies(${_target} pip_rc) add_dependencies(${_target} pip_rc)
@@ -186,12 +171,10 @@ if (NOT DEFINED PIP_CMG)
if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM)) if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM))
set(PIP_CMG "pip_cmg") set(PIP_CMG "pip_cmg")
set(PIP_RC "pip_rc") set(PIP_RC "pip_rc")
set(PIP_TR "pip_tr")
set(PIP_DEPLOY_TOOL "deploy_tool") set(PIP_DEPLOY_TOOL "deploy_tool")
else() else()
set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg") set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg")
set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc") set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc")
set(PIP_TR "${CMAKE_CURRENT_BINARY_DIR}/utils/translator/pip_tr")
set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool") set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool")
endif() endif()
endif() endif()
@@ -208,6 +191,7 @@ set(PIP_INCLUDES "${CMAKE_CURRENT_BINARY_DIR}")
foreach(F ${PIP_FOLDERS}) foreach(F ${PIP_FOLDERS})
if (IS_DIRECTORY "${F}") if (IS_DIRECTORY "${F}")
list(APPEND PIP_INCLUDES "${F}") list(APPEND PIP_INCLUDES "${F}")
#include_directories("${F}")
endif() endif()
endforeach(F) endforeach(F)
@@ -250,11 +234,26 @@ if(PIP_MATH_YN)
add_definitions(-DPIP_MATH_YN) add_definitions(-DPIP_MATH_YN)
endif() endif()
# Check if RT timers exists
set(CMAKE_REQUIRED_INCLUDES time.h)
set(CMAKE_REQUIRED_LIBRARIES )
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT PIP_FREERTOS))
list(APPEND LIBS_MAIN rt)
set(CMAKE_REQUIRED_LIBRARIES rt)
endif()
CHECK_FUNCTION_EXISTS(timer_create PIP_TIMER_RT_0)
CHECK_FUNCTION_EXISTS(timer_settime PIP_TIMER_RT_1)
CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2)
# Check if build debug version # Check if build debug version
if (PIP_BUILD_DEBUG) if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
add_definitions(-DPIP_DEBUG) add_definitions(-DPIP_DEBUG)
else() else()
set(PIP_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif() endif()
@@ -282,14 +281,9 @@ endif()
# Check if ICU used for PIString and PIChar # Check if ICU used for PIString and PIChar
set(PIP_ICU "no") set(PIP_ICU "no")
if(ICU) if(ICU)
pip_find_lib(icuuc) set(PIP_ICU "yes")
if (icuuc_FOUND) add_definitions(-DPIP_ICU)
set(PIP_ICU "yes") list(APPEND LIBS_MAIN icuuc)
add_definitions(-DPIP_ICU)
list(APPEND LIBS_MAIN icuuc)
else()
message(STATUS "Warning: ICU requested, but not found. Build without ICU")
endif()
endif() endif()
@@ -313,6 +307,15 @@ list(APPEND HDRS ${_PIP_DEFS_FILE})
#message("${_PIP_DEFS_CHANGED}") #message("${_PIP_DEFS_CHANGED}")
# Check if RT timers exists
if(PIP_TIMER_RT_0 AND PIP_TIMER_RT_1 AND PIP_TIMER_RT_2)
set(PIP_TIMERS "Thread, ThreadRT, Pool")
add_definitions(-DPIP_TIMER_RT)
else()
set(PIP_TIMERS "Thread, Pool")
endif()
# Add main library # Add main library
if(APPLE) if(APPLE)
@@ -323,27 +326,23 @@ if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include") #message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include") #message("${ANDROID_NDK}/sysroot/usr/include")
endif() endif()
if(NOT PIP_FREERTOS) if(NOT PIP_FREERTOS)
if(WIN32) if(WIN32)
if(${C_COMPILER} STREQUAL "cl.exe") if(${C_COMPILER} STREQUAL "cl.exe")
else()
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
endif()
else() else()
list(APPEND LIBS_MAIN dl) list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
if(DEFINED ENV{QNX_HOST}) endif()
list(APPEND LIBS_MAIN socket) else()
else() list(APPEND LIBS_MAIN dl)
if (NOT DEFINED ANDROID_PLATFORM) if(DEFINED ENV{QNX_HOST})
list(APPEND LIBS_MAIN pthread util) list(APPEND LIBS_MAIN socket)
if (NOT APPLE) else()
list(APPEND LIBS_MAIN rt) if (NOT DEFINED ANDROID_PLATFORM)
endif() list(APPEND LIBS_MAIN pthread util)
endif()
endif() endif()
endif() endif()
endif() endif()
endif()
set(PIP_LIBS) set(PIP_LIBS)
if(PIP_FREERTOS) if(PIP_FREERTOS)
set(PIP_LIBS ${LIBS_MAIN}) set(PIP_LIBS ${LIBS_MAIN})
@@ -366,7 +365,7 @@ endif()
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS}")
pip_module(main "${LIBS_MAIN}" "PIP main library" "" "${PIP_3PL_DIR}/BLAKE2" "") pip_module(main "${LIBS_MAIN}" "PIP main library" "" "" "")
generate_export_header(pip) generate_export_header(pip)
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h") list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h")
@@ -377,254 +376,131 @@ foreach(_m ${PIP_SRC_MODULES})
endforeach() endforeach()
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS) set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS)
# Override containers minimum bytes allocation
if(NOT "x${PIP_CONTAINERS_MIN_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MIN_ALLOC=${PIP_CONTAINERS_MIN_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MIN_ALLOC = ${PIP_CONTAINERS_MIN_ALLOC}")
endif()
# Override containers maximum bytes for power of two expansion, may be bytes or X_KiB, or X_MiB
if(NOT "x${PIP_CONTAINERS_MAX_POT_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MAX_POT_ALLOC=${PIP_CONTAINERS_MAX_POT_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MAX_POT_ALLOC = ${PIP_CONTAINERS_MAX_POT_ALLOC}")
endif()
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
if (NOT PIP_FREERTOS) if (NOT PIP_FREERTOS)
if (PIP_BUILD_CONSOLE)
pip_module(console "" "PIP console support" "" "" "")
endif()
if (PIP_BUILD_USB) pip_module(console "" "PIP console support" "" "" "")
pip_find_lib(usb)
if(usb_FOUND)
pip_module(usb "usb" "PIP usb support" "" "" "") pip_find_lib(usb)
endif() if(usb_FOUND)
pip_module(usb "usb" "PIP usb support" "" "" "")
endif() endif()
if (PIP_BUILD_COMPRESS) pip_find_lib(zlib NAMES z zlib)
pip_find_lib(zlib NAMES z zlib) if(zlib_FOUND)
if(zlib_FOUND) pip_module(compress "zlib" "PIP compression support" "" "" "")
pip_module(compress "zlib" "PIP compression support" "" "" "")
endif()
endif() endif()
if (PIP_BUILD_CRYPT) pip_find_lib(sodium)
pip_find_lib(sodium) if(sodium_FOUND)
if(sodium_FOUND) pip_module(crypt "sodium" "PIP crypt support" "" "" "")
pip_module(crypt "sodium" "PIP crypt support" "" "" "") pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
endif()
endif() endif()
if (PIP_BUILD_FFTW) # Check if PIP support fftw3 for PIFFT using in math module
# Check if PIP support fftw3 for PIFFT using in math module set(FFTW_LIB_NAME fftw3)
set(FFTW_LIB_NAME fftw3) set(FFTW_LIB_SUFFIXES "" "f" "l" "q")
set(FFTW_LIB_SUFFIXES "" "f" "l" "q") set(FFTW_LIB_SUFFIXES2 "" "-3")
set(FFTW_LIB_SUFFIXES2 "" "-3") set(FFTW_LIBS)
set(FFTW_LIBS) set(FFTW_ABS_LIBS)
set(FFTW_ABS_LIBS) set(CMAKE_REQUIRED_INCLUDES fftw3.h)
set(CMAKE_REQUIRED_INCLUDES fftw3.h) foreach(FFTW_S_ IN LISTS FFTW_LIB_SUFFIXES)
foreach(FFTW_S_ IN LISTS FFTW_LIB_SUFFIXES) set(FFTW_BREAK false)
set(FFTW_BREAK false) foreach(FFTW_S2_ IN LISTS FFTW_LIB_SUFFIXES2)
foreach(FFTW_S2_ IN LISTS FFTW_LIB_SUFFIXES2) if(NOT FFTW_BREAK)
if(NOT FFTW_BREAK) set(FFTW_CLN "${FFTW_LIB_NAME}${FFTW_S_}${FFTW_S2_}")
set(FFTW_CLN "${FFTW_LIB_NAME}${FFTW_S_}${FFTW_S2_}") set(FFTW_CLNT "${FFTW_LIB_NAME}${FFTW_S_}_threads${FFTW_S2_}")
set(FFTW_CLNT "${FFTW_LIB_NAME}${FFTW_S_}_threads${FFTW_S2_}") find_library(${FFTW_CLN}_LIBRARIES ${FFTW_CLN})
find_library(${FFTW_CLN}_LIBRARIES ${FFTW_CLN}) find_library(${FFTW_CLNT}_LIBRARIES ${FFTW_CLNT})
find_library(${FFTW_CLNT}_LIBRARIES ${FFTW_CLNT}) set(${FFTW_CLN}_FOUND FALSE)
set(${FFTW_CLN}_FOUND FALSE) set(${FFTW_CLNT}_FOUND FALSE)
set(${FFTW_CLNT}_FOUND FALSE) if(${FFTW_CLN}_LIBRARIES)
if(${FFTW_CLN}_LIBRARIES) set(${FFTW_CLN}_FOUND TRUE)
set(${FFTW_CLN}_FOUND TRUE) list(APPEND FFTW_LIBS "${FFTW_CLN}")
list(APPEND FFTW_LIBS "${FFTW_CLN}") list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}")
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLN}_LIBRARIES}") set(${FFTW_CLN}_CTS "${FFTW_CLN}")
set(${FFTW_CLN}_CTS "${FFTW_CLN}") if(${FFTW_CLNT}_FLIBRARIES)
if(${FFTW_CLNT}_FLIBRARIES) set(${FFTW_CLNT}_FOUND TRUE)
set(${FFTW_CLNT}_FOUND TRUE) list(APPEND FFTW_LIBS "${FFTW_CLNT}")
list(APPEND FFTW_LIBS "${FFTW_CLNT}") list(APPEND FFTW_ABS_LIBS "${${FFTW_CLNT}_LIBRARIES}")
list(APPEND FFTW_ABS_LIBS "${${FFTW_CLNT}_LIBRARIES}") list(APPEND ${FFTW_CLN}_CTS "${FFTW_CLNT}")
list(APPEND ${FFTW_CLN}_CTS "${FFTW_CLNT}") endif()
endif() set(CMAKE_REQUIRED_LIBRARIES ${${FFTW_CLN}_CTS})
set(CMAKE_REQUIRED_LIBRARIES ${${FFTW_CLN}_CTS}) CHECK_FUNCTION_EXISTS(fftw${FFTW_S_}_make_planner_thread_safe ${FFTW_CLN}_TSFE)
CHECK_FUNCTION_EXISTS(fftw${FFTW_S_}_make_planner_thread_safe ${FFTW_CLN}_TSFE) add_definitions(-DPIP_FFTW${FFTW_S_})
add_definitions(-DPIP_FFTW${FFTW_S_}) if(${FFTW_CLN}_TSFE)
if(${FFTW_CLN}_TSFE) add_definitions(-DPIP_FFTW${FFTW_S_}_THREADSAFE)
add_definitions(-DPIP_FFTW${FFTW_S_}_THREADSAFE) else()
else() message(STATUS "Warning: PIFFTW${FFTW_S_}::preparePlan was not threadsafe")
message(STATUS "Warning: PIFFTW${FFTW_S_}::preparePlan was not threadsafe")
endif()
endif() endif()
endif() endif()
endforeach() endif()
endforeach() endforeach()
if(FFTW_LIBS) endforeach()
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "") if(FFTW_LIBS)
endif() pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "")
endif() endif()
if (PIP_BUILD_OPENCL) find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x") if(OpenCL_FOUND)
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}") set(_opencl_lib OpenCL::OpenCL)
if(${CMAKE_VERSION} VERSION_LESS "3.7.0")
target_link_libraries(_opencl_lib OpenCL)
endif() endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
if(OpenCL_FOUND) if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}") set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
endif()
pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif() endif()
pip_module(opencl "${_opencl_lib}" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif() endif()
if (PIP_BUILD_IO_UTILS) if(sodium_FOUND)
if(sodium_FOUND) pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)") else()
else() pip_module(io_utils "" "PIP I/O support" "" "" "")
pip_module(io_utils "" "PIP I/O support" "" "" "")
endif()
endif() endif()
if (PIP_BUILD_LUA) # Lua module
# Lua module set(_lua_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/3rd/lua")
set(_lua_src_dir "${PIP_3PL_DIR}/lua") set(_lua_bri_dir "${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd")
set(_lua_src_hdr "${_lua_src_dir}/lua.hpp" "${_lua_src_dir}/lua.h" "${_lua_src_dir}/luaconf.h" "${_lua_src_dir}/lualib.h") set(_lua_src_hdr "${_lua_src_dir}/lua.hpp" "${_lua_src_dir}/lua.h" "${_lua_src_dir}/luaconf.h" "${_lua_src_dir}/lualib.h")
pip_module(lua "" "PIP Lua support" "${_lua_src_dir};${PIP_3PL_DIR}" "${_lua_src_dir}" " (internal)") pip_module(lua "" "PIP Lua support" "${_lua_src_dir};${_lua_bri_dir}" "${_lua_src_dir}" " (internal)")
target_include_directories(pip_lua PUBLIC "${_lua_src_dir}") target_include_directories(pip_lua PUBLIC "${_lua_src_dir}" "${_lua_bri_dir}")
if (WIN32) if (WIN32)
target_compile_definitions(pip_lua PRIVATE LUA_BUILD_AS_DLL LUA_CORE) target_compile_definitions(pip_lua PRIVATE LUA_BUILD_AS_DLL LUA_CORE)
else()
target_compile_definitions(pip_lua PRIVATE LUA_USE_POSIX)
endif()
list(APPEND HDR_DIRS "${PIP_3PL_DIR}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr})
endif() endif()
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr})
if (PIP_BUILD_HTTP_SERVER)
# libmicrohttpd
pip_find_lib(microhttpd HINTS "${MINGW_LIB}")
if (microhttpd_FOUND)
set(_microhttpd_add_libs microhttpd)
if(WIN32)
if("${C_COMPILER}" STREQUAL "cl.exe")
else()
list(APPEND _microhttpd_add_libs ws2_32)
endif()
else()
list(APPEND _microhttpd_add_libs dl)
find_library(tls_lib gnutls)
if (tls_lib)
set(gnutls_FOUND TRUE)
set(gnutls_LIBRARIES "${tls_lib}")
list(APPEND _microhttpd_add_libs gnutls)
endif()
if(DEFINED ENV{QNX_HOST})
list(APPEND _microhttpd_add_libs socket)
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND _microhttpd_add_libs pthread util)
endif()
endif()
endif()
#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
endif()
endif()
if (PIP_BUILD_HTTP_CLIENT)
# libcurl
pip_find_lib(curl HINTS "${MINGW_LIB}")
if (curl_FOUND)
pip_module(http_client curl "PIP HTTP client" "" "" "")
endif()
endif()
# Test program # Test program
if(PIP_UTILS) if(PIP_UTILS)
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp")
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp" "ccm.h" "ccm.cpp")
#target_link_libraries(pip_plugin pip) #target_link_libraries(pip_plugin pip)
if (NOT DEFINED ANDROID_PLATFORM) add_executable(pip_test "main.cpp")
if(microhttpd_FOUND AND curl_FOUND) target_link_libraries(pip_test pip)
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server pip_http_client)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
endif()
endif()
endif()
endif() endif()
else() else()
pip_module(crypt "" "PIP crypt support" "" "" "")
if (PIP_BUILD_CRYPT) pip_module(compress "" "PIP compression support" "" "" "")
pip_module(crypt "" "PIP crypt support" "" "" "") pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
endif()
if (PIP_BUILD_COMPRESS)
pip_module(compress "" "PIP compression support" "" "" "")
endif()
if (PIP_BUILD_IO_UTILS)
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
endif()
endif() endif()
endif() endif()
string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}") string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}")
target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"") target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"")
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
add_subdirectory("utils/qt_support")
add_subdirectory("utils/translator")
add_subdirectory("utils/value_tree_translator")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
# Translations
set(PIP_LANG)
if (NOT CROSSTOOLS)
# pip_translation(PIP_LANG lang/pip_ru.ts)
# add_custom_target(pip_lang SOURCES "${PIP_LANG}")
file(GLOB PIP_LANG "lang/*.btf")
endif()
# Install # Install
# Check if system or local install will be used (to system install use "-DLIB=" argument of cmake) # Check if system or local install will be used (to system install use "-DLIB=" argument of cmake)
if(NOT LOCAL) if(NOT LOCAL)
@@ -632,9 +508,6 @@ if(NOT LOCAL)
if(MINGW) if(MINGW)
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip) install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${MINGW_INCLUDE}/../share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip)
endif() endif()
@@ -648,7 +521,6 @@ if(NOT LOCAL)
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/translator")
endif() endif()
else() else()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include)
@@ -656,9 +528,6 @@ if(NOT LOCAL)
else() else()
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
endif() endif()
@@ -674,9 +543,6 @@ else()
install(TARGETS ${PIP_MODULES} DESTINATION lib) install(TARGETS ${PIP_MODULES} DESTINATION lib)
endif() endif()
install(FILES ${HDRS} DESTINATION include/pip) install(FILES ${HDRS} DESTINATION include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip)
endif() endif()
@@ -685,6 +551,29 @@ endif()
file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in") file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in")
install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules) install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules)
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
shstk_is_parent_exists(_pe) shstk_is_parent_exists(_pe)
if (_pe) if (_pe)
@@ -699,18 +588,18 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
find_package(Doxygen) find_package(Doxygen)
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
set(DOXY_DEFINES "${PIP_EXPORTS}") set(DOXY_DEFINES "${PIP_EXPORTS}")
foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua" "http_server" "http_client") foreach (_m "console" "usb" "compress" "crypt" "cloud" "fftw" "opencl" "io_utils" "lua")
string(TOUPPER "${_m}" _mdef) string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT") list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach() endforeach()
set(DOXY_PROJECT_NUMBER "${PIP_VERSION}") set(DOXY_PROJECT_NUMBER "${pip_VERSION}")
set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"") set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"") set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"") set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"")
set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"") set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"") set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/3rd\"") set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc") set(DOXY_DOMAIN "${pip_DOMAIN}.${PROJECT_NAME}.doc")
if ("x${DOC_LANG}" STREQUAL "x") if ("x${DOC_LANG}" STREQUAL "x")
set(DOXY_OUTPUT_LANGUAGE English) set(DOXY_OUTPUT_LANGUAGE English)
set(DOXY_OUTPUT_DIR en) set(DOXY_OUTPUT_DIR en)
@@ -755,11 +644,10 @@ macro(expand_to_length _out _str _len)
endmacro() endmacro()
list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES}) list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
list(REMOVE_DUPLICATES LIBS_STATUS)
message("----------PIP----------") message("----------PIP----------")
message(" Version: ${PIP_VERSION} ") message(" Version: ${pip_VERSION} ")
message(" Linkage: ${PIP_LIB_TYPE_MSG}") message(" Linkage: ${pip_LIB_TYPE_MSG}")
message(" Type : ${CMAKE_BUILD_TYPE}") message(" Type : ${pip_BUILD_TYPE}")
if (NOT LOCAL) if (NOT LOCAL)
message(" Install: \"${CMAKE_INSTALL_PREFIX}\"") message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else() else()
@@ -771,6 +659,7 @@ message("")
message(" Options:") message(" Options:")
message(" std::iostream: ${PIP_STD_IOSTREAM}") message(" std::iostream: ${PIP_STD_IOSTREAM}")
message(" ICU strings : ${PIP_ICU}") message(" ICU strings : ${PIP_ICU}")
message(" Timer types : ${PIP_TIMERS}")
message(" Introspection: ${PIP_INTROSPECTION}") message(" Introspection: ${PIP_INTROSPECTION}")
message(" Coverage : ${PIP_COVERAGE}") message(" Coverage : ${PIP_COVERAGE}")
if(INTROSPECTION) if(INTROSPECTION)

View File

@@ -33,10 +33,10 @@ You should add ${<out_var>} to your target.
## Documentation ## Documentation
[🇺🇸 Online documentation](https://shstk.ru/pip/html/en/index.html) [🇺🇸 Online documentation](https://shs.tools/pip/html/en/index.html)
[🇺🇸 Qt-help](https://shstk.ru/pip/pip_en.qch) [🇺🇸 Qt-help](https://shs.tools/pip/pip_en.qch)
[🇷🇺 Онлайн документация](https://shstk.ru/pip/html/ru/index.html) [🇷🇺 Онлайн документация](https://shs.tools/pip/html/ru/index.html)
[🇷🇺 Qt-help](https://shstk.ru/pip/pip_ru.qch) [🇷🇺 Qt-help](https://shs.tools/pip/pip_ru.qch)

View File

@@ -9,11 +9,8 @@ Create imported targets:
* PIP::FFTW * PIP::FFTW
* PIP::OpenCL * PIP::OpenCL
* PIP::IOUtils * PIP::IOUtils
* PIP::ClientServer
* PIP::Cloud * PIP::Cloud
* PIP::Lua * PIP::Lua
* PIP::HTTPClient
* PIP::HTTPServer
These targets include directories and depends on These targets include directories and depends on
main library main library
@@ -23,37 +20,40 @@ main library
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
include(SHSTKMacros) include(SHSTKMacros)
shstk_set_find_dirs(PIP) shstk_set_find_dirs(pip)
if(PIP_DIR)
list(APPEND pip_LIBDIR "${PIP_DIR}/lib")
list(APPEND pip_INCDIR "${PIP_DIR}/include/pip")
list(APPEND pip_BINDIR "${PIP_DIR}/bin")
endif()
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua;http_client;http_server") set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
if (BUILDING_PIP) if (BUILDING_pip)
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua;pip_http_client;pip_http_server") #set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua")
#set(_bins "pip_cmg;pip_rc;deploy_tool") #set(_bins "pip_cmg;pip_rc;deploy_tool")
#get_target_property(_path pip BINARY_DIR) #get_target_property(_path pip BINARY_DIR)
#get_target_property(_path pip LIBRARY_OUTPUT_NAME) #get_target_property(_path pip LIBRARY_OUTPUT_NAME)
#message("${_path}") #message("${_path}")
#set(PIP_LIBRARY "$<TARGET_FILE_DIR:pip>/$<TARGET_FILE_NAME:pip>" CACHE STRING "") #set(PIP_LIBRARY "$<TARGET_FILE_DIR:pip>/$<TARGET_FILE_NAME:pip>" CACHE STRING "")
set(PIP_LIBRARY pip CACHE STRING "") set(PIP_LIBRARY pip CACHE STRING "")
set(PIP_FOUND ON CACHE BOOL "") set(PIP_FOUND ON CACHE BOOL "")
else() else()
find_library(PIP_LIBRARY pip HINTS ${PIP_LIBDIR}) find_library(PIP_LIBRARY pip HINTS ${pip_LIBDIR})
foreach (_l ${__libs}) foreach (_l ${__libs})
find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${PIP_LIBDIR}) find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${pip_LIBDIR})
endforeach() endforeach()
endif() endif()
if (BUILDING_PIP AND (NOT CMAKE_CROSSCOMPILING)) if (BUILDING_pip AND (NOT CMAKE_CROSSCOMPILING))
set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "") set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "")
set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "") set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "")
set(PIP_TR "$<TARGET_FILE_DIR:pip_tr>/$<TARGET_FILE_NAME:pip_tr>" CACHE STRING "")
set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "") set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "")
else() else()
find_program(PIP_CMG pip_cmg${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG}) find_program(PIP_CMG pip_cmg${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_RC pip_rc${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG}) find_program(PIP_RC pip_rc${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_TR pip_tr${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG}) find_program(PIP_DEPLOY_TOOL deploy_tool${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_DEPLOY_TOOL deploy_tool${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
endif() endif()
if (NOT PIP_LIBRARY) if (NOT PIP_LIBRARY)
if(PIP_FIND_REQUIRED) if(PIP_FIND_REQUIRED)
@@ -63,7 +63,7 @@ if (NOT PIP_LIBRARY)
endif() endif()
set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}") set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}")
set(_PIP_ADD_LIBS_ "") set(_PIP_ADD_LIBS_ "")
if (NOT BUILDING_PIP) if (NOT BUILDING_pip)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
find_library(DL_LIBRARY dl) find_library(DL_LIBRARY dl)
list(APPEND PIP_LIBRARY ${DL_LIBRARY}) list(APPEND PIP_LIBRARY ${DL_LIBRARY})
@@ -80,26 +80,23 @@ if (NOT BUILDING_PIP)
endif() endif()
endif() endif()
if (NOT BUILDING_PIP) if (NOT BUILDING_pip)
shstk_find_header(PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}") shstk_find_header(pip PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}")
set(PIP_INCLUDES "${PIP_INCLUDES}" CACHE STRING "") set(PIP_INCLUDES "${pip_INCLUDES}" CACHE STRING "")
endif() endif()
if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION) if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION)
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!") message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
endif() endif()
set(__module_usb USB ) set(__module_usb USB )
set(__module_console Console ) set(__module_console Console )
set(__module_crypt Crypt ) set(__module_crypt Crypt )
set(__module_fftw FFTW ) set(__module_fftw FFTW )
set(__module_compress Compress ) set(__module_compress Compress )
set(__module_opencl OpenCL ) set(__module_opencl OpenCL )
set(__module_io_utils IOUtils ) set(__module_io_utils IOUtils )
set(__module_client_server ClientServer) set(__module_cloud Cloud )
set(__module_cloud Cloud ) set(__module_lua Lua )
set(__module_lua Lua )
set(__module_http_client HTTPClient )
set(__module_http_server HTTPServer )
foreach (_l ${__libs}) foreach (_l ${__libs})
set( __inc_${_l} "") set( __inc_${_l} "")
@@ -107,15 +104,14 @@ foreach (_l ${__libs})
set(__libs_${_l} "") set(__libs_${_l} "")
endforeach() endforeach()
set(__deps_io_utils "PIP::Crypt" ) set(__deps_io_utils "PIP::Crypt")
set(__deps_client_server "PIP::IOUtils") set(__deps_cloud "PIP::IOUtils")
set(__deps_cloud "PIP::IOUtils")
if (BUILDING_PIP) if (BUILDING_pip)
if (NOT SET_TARGETS_PIP) if (NOT SET_TARGETS_pip)
set(SET_TARGETS_PIP ON CACHE BOOL "") set(SET_TARGETS_pip ON CACHE BOOL "")
#message("create aliases") #message("create aliases")
if((NOT TARGET PIP) AND PIP_LIBRARY) if((NOT TARGET PIP) AND PIP_LIBRARY)
#message("alias PIP = pip") #message("alias PIP = pip")
@@ -137,7 +133,7 @@ else()
add_library(PIP UNKNOWN IMPORTED) add_library(PIP UNKNOWN IMPORTED)
set_target_properties(PIP PROPERTIES set_target_properties(PIP PROPERTIES
IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}" IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}"
INTERFACE_INCLUDE_DIRECTORIES "${PIP_INCLUDES}" INTERFACE_INCLUDE_DIRECTORIES "${pip_INCLUDES}"
INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}") INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}")
#message("imported PIP = ${PIP_LIBRARY}") #message("imported PIP = ${PIP_LIBRARY}")
endif() endif()

View File

@@ -18,14 +18,6 @@
Generate C++ files for resource file Generate C++ files for resource file
You should add ${<out_var>} to your target You should add ${<out_var>} to your target
pip_translation(<out_var> ts_file)
Generate *.btf (binary translation file) from *.ts file
You should add ${<out_var>} to your target and then install it to somewhere
for later loading in runtime by PITranslator
]] ]]
@@ -127,34 +119,3 @@ macro(pip_resources RESULT INPUT)
VERBATIM) VERBATIM)
endmacro() endmacro()
macro(pip_translation RESULT INPUT)
#message(STATUS "src = ${CCM_SRC}")
#message(STATUS "result = ${RESULT}")
#message(STATUS "options = \"${CCM_OPTS}\"")
get_filename_component(BTF_FILENAME "${INPUT}" NAME_WE)
set(BTF_FILENAME "${BTF_FILENAME}.btf")
set(BTF_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BTF_FILENAME})
list(APPEND ${RESULT} "${BTF_OUTPUT}")
if(IS_ABSOLUTE "${INPUT}")
set(IN_FILES "${INPUT}")
else()
set(IN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
endif()
#message(STATUS "CCM = ${RESULT}")
if(NOT DEFINED PIP_DLL_DIR)
set(PIP_DLL_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
#message("PIP_TR: ${PIP_TR}")
#message("BTF_OUTPUT: ${BTF_OUTPUT}")
#message("IN_FILES: ${IN_FILES}")
#message("PIP_DLL_DIR: ${PIP_DLL_DIR}")
add_custom_command(OUTPUT ${BTF_OUTPUT}
COMMAND ${PIP_TR}
ARGS -C -o "${BTF_OUTPUT}" "${IN_FILES}"
DEPENDS ${IN_FILES}
WORKING_DIRECTORY ${PIP_DLL_DIR}
COMMENT "Generating ${BTF_FILENAME}"
VERBATIM)
endmacro()

View File

@@ -2282,7 +2282,7 @@ EXTERNAL_GROUPS = YES
# be listed. # be listed.
# The default value is: YES. # The default value is: YES.
EXTERNAL_PAGES = NO EXTERNAL_PAGES = YES
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the dot tool # Configuration options related to the dot tool

View File

@@ -9,14 +9,8 @@ struct S {
}; };
// Operators // Operators
PIByteArray & operator<<(PIByteArray & b, const S & s) { PIByteArray & operator <<(PIByteArray & b, const S & s) {b << s.i << s.f << s.s; return b;}
b << s.i << s.f << s.s; PIByteArray & operator >>(PIByteArray & b, S & s) {b >> s.i >> s.f >> s.s; return b;}
return b;
}
PIByteArray & operator>>(PIByteArray & b, S & s) {
b >> s.i >> s.f >> s.s;
return b;
}
//! [struct] //! [struct]
//! [write] //! [write]
// Write chunk stream // Write chunk stream
@@ -28,7 +22,10 @@ PIVector<float> f;
f << -1. << 2.5 << 11.; f << -1. << 2.5 << 11.;
// write some data to empty stream // write some data to empty stream
PIChunkStream cs; PIChunkStream cs;
cs << cs.chunk(1, int(10)) << cs.chunk(2, PIString("text")) << cs.chunk(4, f) << cs.chunk(3, s); cs << cs.chunk(1, int(10))
<< cs.chunk(2, PIString("text"))
<< cs.chunk(4, f)
<< cs.chunk(3, s);
// now you can take cs.data() and send or place it somewhere ... // now you can take cs.data() and send or place it somewhere ...
//! [write] //! [write]
//! [read] //! [read]
@@ -45,14 +42,14 @@ while (!cs2.atEnd()) {
case 1: i = cs2.getData<int>(); break; case 1: i = cs2.getData<int>(); break;
case 2: str = cs2.getData<PIString>(); break; case 2: str = cs2.getData<PIString>(); break;
case 3: s = cs2.getData<S>(); break; case 3: s = cs2.getData<S>(); break;
case 4: f = cs2.getData<PIVector<float>>(); break; case 4: f = cs2.getData<PIVector<float> >(); break;
} }
} }
piCout << i << str << f << s.i << s.f << s.s; piCout << i << str << f << s.i << s.f << s.s;
//! [read] //! [read]
//! [write_new] //! [write_new]
PIByteArray & operator<<(PIByteArray & s, const S & value) { PIByteArray & operator <<(PIByteArray & s, const S & value) {
PIChunkStream cs; PIChunkStream cs;
cs.add(1, value.i).add(2, value.f).add(3, value.s); cs.add(1, value.i).add(2, value.f).add(3, value.s);
s << cs.data(); s << cs.data();
@@ -60,11 +57,11 @@ PIByteArray & operator<<(PIByteArray & s, const S & value) {
} }
//! [write_new] //! [write_new]
//! [read_new] //! [read_new]
PIByteArray & operator>>(PIByteArray & s, S & value) { PIByteArray & operator >>(PIByteArray & s, S & value) {
PIChunkStream cs; PIChunkStream cs;
if (!cs.extract(s)) return s; if (!cs.extract(s)) return s;
cs.readAll(); cs.readAll();
cs.get(1, value.i).get(2, value.f).get(3, value.s); cs.get(1, value.i).get(2, value.f).get(3, value.s);
return s; return b;
} }
//! [read_new] //! [read_new]

View File

@@ -1,57 +1,54 @@
#include "pip.h" #include "pip.h"
//! [own] //! [own]
inline PICout operator<<(PICout s, const PIByteArray & ba) { inline PICout operator <<(PICout s, const PIByteArray & ba) {
s.space(); // insert space after previous output s.space(); // insert space after previous output
s.quote(); // ONLY if you want to quoted your type s.quote(); // ONLY if you want to quoted your type
s.saveAndSetControls(0); // clear all features and s.setControl(0, true); // clear all features and
// save them to stack, // save them to stack,
// now it`s behavior similar to std::cout // now it`s behavior similar to std::cout
// your output // your output
for (uint i = 0; i < ba.size(); ++i) for (uint i = 0; i < ba.size(); ++i)
s << ba[i]; s << ba[i];
s.restoreControls(); // restore features from stack s.restoreControl(); // restore features from stack
s.quote(); // ONLY if you want to quoted your type s.quote(); // ONLY if you want to quoted your type
return s; return s;
} }
//! [own] //! [own]
// clang-format off
void _() { void _() {
//! [0] //! [0]
using namespace PICoutManipulators;
int a = 10, b = 32, c = 11; int a = 10, b = 32, c = 11;
piCout << a << Hex << b << Bin << c; piCout << a << Hex << b << Bin << c;
// 10 20 1011 // 10 20 1011
piCout << "this" piCout << "this" << "is" << Green << "green" << Default << "word";
<< "is" << Green << "green" << Default << "word";
// this is green word // this is green word
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" << "quotes";
<< "quotes";
// "tab and" "quotes" // "tab and" "quotes"
//! [0] //! [0]
} }
// clang-format on
//! [notifier] //! [notifier]
class A: public PIObject { class A: public PIObject {
PIOBJECT(A) PIOBJECT(A)
public: public:
A() {} A() {}
EVENT_HANDLER2(void, pcf, int, id, PIString *, buff) { piCout << "PICout(" << id << ") finished:" << (*buff); } EVENT_HANDLER2(void, pcf, int, id, PIString*, buff) {
piCout << "PICout(" << id << ") finished:" << (*buff);
}
}; };
int main() { int main() {
A a; A a;
CONNECTU(PICout::Notifier::object(), finished, &a, pcf); CONNECTU(PICout::Notifier::object(), finished, &a, pcf);
PIString buffer = "my buff:"; PIString buffer = "my buff:";
int my_id = PICout::registerExternalBufferID(); PICout(&buffer, 1) << "int 10 ->" << 10 << ", time ->" << PITime::current();
PICout::withExternalBufferAndID(&buffer, my_id) << "int 10 ->" << 10 << ", time ->" << PITime::current();
return 0; return 0;
} }
// PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000) // PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000)

View File

@@ -7,19 +7,19 @@ class SomeIO: public PIIODevice {
public: public:
SomeIO(): PIIODevice() {} SomeIO(): PIIODevice() {}
protected: protected:
bool openDevice() override { bool openDevice() {
// open your device here // open your device here
return if_success; return if_success;
} }
ssize_t readDevice(void * read_to, ssize_t max_size) override { int read(void * read_to, int max_size) {
// read from your device here // read from your device here
return readed_bytes; return readed_bytes;
} }
ssize_t writeDevice(const void * data, ssize_t max_size) override { int write(const void * data, int max_size) {
// write to your device here // write to your device here
return written_bytes; return written_bytes;
} }
void configureFromFullPathDevice(const PIString & full_path) override { void configureFromFullPath(const PIString & full_path) {
// parse full_path and configure device here // parse full_path and configure device here
} }
}; };
@@ -38,7 +38,7 @@ ser.configure("example.conf", "dev");
//! [configureDevice] //! [configureDevice]
class SomeIO: public PIIODevice { class SomeIO: public PIIODevice {
... ...
bool configureDevice(const void * e_main, const void * e_parent) override { bool configureDevice(const void * e_main, const void * e_parent) {
PIConfig::Entry * em = (PIConfig::Entry * )e_main; PIConfig::Entry * em = (PIConfig::Entry * )e_main;
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent; PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep)); setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep));

View File

@@ -1,10 +1,10 @@
#include "pip.h" #include "pip.h"
//! [delimiter] //! [delimiter]
void tfunc(int delim) { void tfunc(void * , int delim) {
piCout << "tick with delimiter" << delim; piCout << "tick with delimiter" << delim;
}; };
void tfunc4(int delim) { void tfunc4(void * , int delim) {
piCout << "tick4 with delimiter" << delim; piCout << "tick4 with delimiter" << delim;
}; };
int main() { int main() {
@@ -13,7 +13,8 @@ int main() {
timer.addDelimiter(4, tfunc4); timer.addDelimiter(4, tfunc4);
timer.start(50); timer.start(50);
piMSleep(200); piMSleep(200);
timer.stopAndWait(); timer.stop();
timer.waitForFinish();
return 0; return 0;
}; };
/* Result: /* Result:
@@ -28,14 +29,14 @@ tick4 with delimiter 4
//! [delimiter] //! [delimiter]
//! [elapsed] //! [elapsed]
int main() { int main() {
PITimeMeasurer tm; PITimer timer;
piMSleep(100); piMSleep(100);
piCout << "elapsed" << tm.elapsed_m() << "ms"; piCout << "elapsed" << timer.elapsed_m() << "ms";
piMSleep(100); piMSleep(100);
piCout << "elapsed" << tm.elapsed_m() << "ms"; piCout << "elapsed" << timer.elapsed_m() << "ms";
tm.reset(); timer.reset();
piMSleep(150); piMSleep(150);
piCout << "elapsed" << tm.elapsed_s() << "s"; piCout << "elapsed" << timer.elapsed_s() << "s";
return 0; return 0;
}; };
/* Result: /* Result:
@@ -46,21 +47,22 @@ elapsed 0.15 s
//! [elapsed] //! [elapsed]
//! [system_time] //! [system_time]
int main() { int main() {
PISystemTime t0; // s = ns = 0 PISystemTime t0; // s = ns = 0
t0.addMilliseconds(200); // s = 0, ns = 200000000 t0.addMilliseconds(200); // s = 0, ns = 200000000
t0.addMilliseconds(900); // s = 1, ns = 100000000 t0.addMilliseconds(900); // s = 1, ns = 100000000
t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0 t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0
t0.sleep(); // sleep for 1 second t0.sleep(); // sleep for 1 second
PISystemTime t1; PISystemTime t1;
t0 = PISystemTime::current(); t0 = currentSystemTime();
piMSleep(500); piMSleep(500);
t1 = PISystemTime::current(); t1 = currentSystemTime();
(t1 - t0).sleep(); // sleep for 500 milliseconds (t1 - t0).sleep(); // sleep for 500 milliseconds
return 0; return 0;
}; };
//! [system_time] //! [system_time]
void _(){ void _() {
}; };

View File

@@ -1,297 +0,0 @@
\~english \page code_model Code generation
\~russian \page code_model Генерация кода
\~english
\~russian
# Введение
Кодогенерация помогает в случаях, когда нужен доступ к строковому представлению
сущностей (классов, перечислений, ...), либо автоматизированная де/сериализация
структур и классов.
Например, необходимо для создания интерфейса получить в готовом виде список
пар "имя" = "значение" от какого-либо перечисления, либо обойти список
вложенных в класс структур с дополнительными метками. Или просто описать
структуру любой сложности, пометить поля номерами и получить готовые операторы
де/сериализации для PIBinaryStream с возможностью будущих изменений и сохранением
обратной совместимости.
# pip_cmg
PIP предоставляет утилиту, которая берет на вход файлы исходного кода, пути
включения, параметры и макросы, и на выходе создает h/cpp пару файлов с
необходимым функционалом. В зависимости от параметров, в этих файлах будут
присутствовать секции:
* метаинформации о сущностях;
* операторы де/сериализации;
* возможность получить PIVariant любого члена структуры по имени.
Параметры обработки:
* -s - не следовать "#include" внутри файлов;
* -I<include_dir> - добавить папку включения (например, -I.. -I../some_dir -I/usr/include);
* -D<define> - добавить макрос, PICODE всегда объявлен (например, -DMY_DEFINE добавит макрос MY_DEFINE).
Параметры создания:
* -A - создать всё;
* -M - создать метаинформацию (имена и типы всех членов, иерархия включения);
* -E - создать перечисления (списки перечислений);
* -S - создать операторы де/сериализации;
* -G - создать методы получения значений переменных по именам;
* -o <output_file> - имя файлов модели без расширения (например, "ccm" - создадутся файлы "ccm.h" и "ccm.cpp")
# CMake
Для автоматизации кодогенерации существует CMake макрос pip_code_model, который сам вызывает pip_cmg и
следит за актуальностью модели.
Формат вызова макроса:
\code{.cmake}
pip_code_model(<out_var> file0 [file1 ...] [OPTIONS opt0 [opt1 ...] ] [NAME name])
\endcode
Параметры:
* out_var - имя переменной, куда будут записаны абсолютные пути сгенерённых файлов;
* file... - файлы для генерации, допускаются относительные или абсолютные пути;
* OPTIONS - передаваемые в pip_cmg параметры, например, "-Es";
* NAME - базовое имя файлов модели, если не указано, то используется "ccm_${PROJECT_NAME}".
Этот макрос сам включает все пути для PIP.
Для получения актуальных параметров pip_cmg можно вызывать "pip_cmg -v".
# Подробности
## Метаинформация
Метаинформация - это текстовое представление всех членов и методов структуры или класса C++.
Для доступа к ним используется PICODEINFO::classes().value("name"), который возвращает
указатель на структуру PICodeInfo::ClassInfo, содержащую всю информацию о сущности.
В любой структуре PICodeInfo есть поле "MetaMap meta", содержащее произвольные
данные, видимые для кодогенератора, но невидимые для компилятора.
Для этого используется макрос PIMETA(), который необходимо вписать после объявления
переменной, метода либо сущности, например:
\code{.cpp}
struct MyStruct: Header PIMETA(type=in,port=5005) {
ushort calcChecksum() const PIMETA(show=true);
bool checkChecksum() const;
void setChecksum();
uchar block_id PIMETA(type=int) = 0;
};
enum FOV { // Поле зрения
fovWide PIMETA(label="Широкое",angle=90),
fovNormal PIMETA(label="Нормальное",angle=60),
fovNarrow PIMETA(label="Узкое",angle=30)
};
\endcode
В этом примере в каждом месте, где указана PIMETA, её можно будет получить через "MetaMap meta".
## Перечисления
Перечисления записываются отдельно, для доступа к ним используется PICODEINFO::enums().value("name"),
который возвращает указатель на структуру PICodeInfo::EnumInfo, содержащую всю информацию о перечеслении.
## Операторы де/сериализации
Эти операторы создаются в h файле для всех сутрктур и классов, в которых есть хотя бы один член,
доступный для работы. Операторы работают с PIBinaryStream в двух вариантах - простом или через PIChunkStream.
Для каждой структуры можно указать режим де/сериализации с помощью фиксированного поля в PIMETA:
* нет указаний - работа через PIChunkStream;
* simple-stream - работа просто через PIBinaryStream;
* no-stream - не создавать операторы.
Например, для структуры
\code{.cpp}
struct DateTime {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
создадутся операторы
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(1, v.seconds);
cs << cs.chunk(2, v.minutes);
cs << cs.chunk(3, v.hours);
cs << cs.chunk(4, v.days);
cs << cs.chunk(5, v.months);
cs << cs.chunk(6, v.years);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: cs.get(v.seconds); break;
case 2: cs.get(v.minutes); break;
case 3: cs.get(v.hours); break;
case 4: cs.get(v.days); break;
case 5: cs.get(v.months); break;
case 6: cs.get(v.years); break;
}
}
return s;
}
\endcode
, где порядок id последовательнен.
Для структуры
\code{.cpp}
struct DateTime PIMETA(simple-stream) {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
создадутся операторы
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
s << v.seconds;
s << v.minutes;
s << v.hours;
s << v.days;
s << v.months;
s << v.years;
return s;
}
BINARY_STREAM_READ (DateTime) {
s >> v.seconds;
s >> v.minutes;
s >> v.hours;
s >> v.days;
s >> v.months;
s >> v.years;
return s;
}
\endcode
Для структуры
\code{.cpp}
struct DateTime PIMETA(no-stream) {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
не создадутся операторы
В режиме работы через PIChunkStream также можно указать индивидуальные id,
что очень полезно для сохранения обратной совместимости структур разных версий:
Для структуры
\code{.cpp}
struct DateTime {
PIMETA(id=10) uchar seconds;
PIMETA(id=11) uchar minutes;
PIMETA(id=12) uchar hours;
PIMETA(id=20) uchar days;
PIMETA(id=21) uchar months;
PIMETA(id=22) uchar years;
};
\endcode
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(10, v.seconds);
cs << cs.chunk(11, v.minutes);
cs << cs.chunk(12, v.hours);
cs << cs.chunk(20, v.days);
cs << cs.chunk(21, v.months);
cs << cs.chunk(22, v.years);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 10: cs.get(v.seconds); break;
case 11: cs.get(v.minutes); break;
case 12: cs.get(v.hours); break;
case 20: cs.get(v.days); break;
case 21: cs.get(v.months); break;
case 22: cs.get(v.years); break;
}
}
return s;
}
\endcode
Если в этом режиме какую-либо переменную надо проигнорировать, то вместо
числа id можно указать "-":
\code{.cpp}
struct DateTime {
PIMETA(id=10) uchar seconds;
PIMETA(id=11) uchar minutes;
PIMETA(id=-) uchar hours;
PIMETA(id=20) uchar days;
PIMETA(id=21) uchar months;
PIMETA(id=-) uchar years;
};
\endcode
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(10, v.seconds);
cs << cs.chunk(11, v.minutes);
cs << cs.chunk(20, v.days);
cs << cs.chunk(21, v.months);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 10: cs.get(v.seconds); break;
case 11: cs.get(v.minutes); break;
case 20: cs.get(v.days); break;
case 21: cs.get(v.months); break;
}
}
return s;
}
\endcode
# Интеграция в проект
При использовании CMake достаточно включить содержимое переменной out_var в приложение
или библиотеку, и включить через "#include" сгенерированный заголовочный файл в нужном месте.
После этого перечисления и метаинформация будут загружены в момент запуска, до int main(),
а операторы станут доступны через заголовочный файл.
CMakeLists.txt:
\code{.cmake}
project(myapp)
pip_code_model(CCM "structures.h" OPTIONS "-EMs")
add_executable(${PROJECT_NAME} ${CPPS} ${CCM})
\endcode
C++:
\code{.cpp}
#include "ccm_myapp.h"
...
PICodeInfo::EnumInfo * ei = PICODEINFO::enums().value("MyEnum", 0);
if (ei) {
ei->members.forEach([](const PICodeInfo::EnumeratorInfo & e){piCout << e.name << "=" << e.value;});
}
\endcode

View File

@@ -1,125 +0,0 @@
\~english \page iostream Input/Output stream
\~russian \page iostream Поток ввода/вывода
\~english
\~russian
%PIBinaryStream представляет собой интерфейс бинарной сериализации.
Не может быть использован в чистом виде, только в виде миксина или
готовых классов: PIByteArray и PIIOBinaryStream.
Используется для сохранения или чтения любых данных. Простые типы читаются/пишутся
как блоки памяти, если не созданы конкретные операторы. Сложные типы
([нетривиальные](https://ru.cppreference.com/w/cpp/types/is_trivially_copyable))
обязаны иметь операторы ввода/вывода, иначе возникнет ошибка компиляции.
Также поддерживаются контейнеры с типами по таким же правилам.
Перечисления интерпретируются как int, логические типы как один байт.
Операторы сохранения добавляют данные в конец потока, а операторы извлечения
берут данные из его начала.
Для облегчения написания операторов есть макросы:
* BINARY_STREAM_FRIEND(T) - объявить операторы с доступом к приватному
содержимому типа T, необязателен;
* BINARY_STREAM_WRITE(T) - запись в поток, "s" - объект потока, "v" - объект типа T;
* BINARY_STREAM_READ(T) - чтение из потока, "s" - объект потока, "v" - объект типа T.
Пример:
\~\code{.cpp}
#include <pibytearray.h>
class MyType {
BINARY_STREAM_FRIEND(MyType);
public:
void setInt(int v) {m_i = v;}
int getInt() const {return m_i;}
void setString(PIString v) {m_s = v;}
PIString getString() const {return m_s;}
private:
int m_i = 0;
PIString m_s;
};
BINARY_STREAM_WRITE(MyType) {s << v.m_i << v.m_s; return s;}
BINARY_STREAM_READ (MyType) {s >> v.m_i >> v.m_s; return s;}
int main(int argc, char * argv[]) {
MyType t_read, t_write;
t_write.setInt(10);
t_write.setString("text");
PIByteArray data;
data << t_write;
piCout << data.toHex();
data >> t_read;
piCout << t_read.getInt() << t_read.getString();
piCout << data.toHex();
}
\endcode
\~english Result:
\~russian Результат:
\~\code{.cpp}
0a000000040000007400650078007400
10 text
\endcode
\~english
For store/restore custom data blocks this is PIMemoryBlock class. Stream
operators of this class simply store/restore data block to/from stream:
\~russian
Для сохранения/извлечения блоков произвольных данных используется класс PIMemoryBlock.
Потоковые операторы для него просто сохраняют/извлекают блоки байтов в/из потока:
\~\code{.cpp}
float a_read[10], a_write[10];
for (int i = 0; i < 10; ++i) {
a_read [i] = 0.f;
a_write[i] = i / 10.f;
}
PIByteArray data;
data << PIMemoryBlock(a_write, 10 * sizeof(float));
piCout << data.toHex();
data >> PIMemoryBlock(a_read, 10 * sizeof(float));
for (int i = 0; i < 10; ++i)
piCout << a_read[i];
\endcode
\~english Result:
\~russian Результат:
\~\code{.cpp}
00000000cdcccc3dcdcc4c3e9a99993ecdcccc3e0000003f9a99193f3333333fcdcc4c3f6666663f
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
\endcode
\~english
\~russian
Если при чтении из потока не хватило данных (например, закончился массив или файл), то проверка
объекта потока на wasReadError() вернёт true. Рекомендуется делать эту проверку после чтения
данных для корректной обработки ошибки.

View File

@@ -3,19 +3,19 @@
\~english \~english
* Direct output to console (\a PICout) * direct output to console (\a PICout)
* Containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet) * containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* Byte array (\a PIByteArray) * byte array (\a PIByteArray)
* Serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON) * serialization (\a PIChunkStream)
* String (\a PIConstChars, \a PIString, \a PIStringList) * string (\a PIConstChars, \a PIString, \a PIStringList)
* Base object (events and handlers) (\a PIObject) * base object (events and handlers) (\a PIObject)
* Multithreading * multithreading
* thread (\a PIThread) * thread (\a PIThread)
* blocking (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock) * blocking (\a PIMutex, \a PISpinlock)
* executor (\a PIThreadPoolExecutor, \a PIThreadPoolLoop) * executor (\a PIThreadPoolExecutor)
* blocking dequeue (\a PIBlockingDequeue) * blocking dequeue (\a PIBlockingDequeue)
* timer (\a PITimer) * timer (\a PITimer)
* Tiling console (with widgets) (\a PIScreen) * tiling console (with widgets) (\a PIScreen)
* simple text rows * simple text rows
* scroll bar * scroll bar
* list * list
@@ -37,8 +37,7 @@
* peering net node (\a PIPeer) * peering net node (\a PIPeer)
* connection quality diagnotic (\a PIDiagnostics) * connection quality diagnotic (\a PIDiagnostics)
* Run-time libraries * Run-time libraries
* external process (\a PIProcess) * abstract (\a PILibrary)
* external library (\a PILibrary)
* plugin (\a PIPluginLoader) * plugin (\a PIPluginLoader)
* Mathematics * Mathematics
* complex numbers * complex numbers
@@ -50,33 +49,24 @@
* CRC checksum (\a PICRC) * CRC checksum (\a PICRC)
* Fourier transform (\a PIFFTW, \a PIFFT) * Fourier transform (\a PIFFTW, \a PIFFT)
* expression evaluator (\a PIEvaluator) * expression evaluator (\a PIEvaluator)
* Application-level * command-line arguments parser (\a PICLI)
* command-line arguments parser (\a PICLI) * process (\a PIProcess)
* system resources monitoring (\a PISystemMonitor)
* single-instance application control (\a PISingleApplication)
* high-level log (\a PILog)
* translation support (\a PITranslator)
* State machine ([By stantard](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* High-level TCP client-server
* server (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* client (\a PIClientServer::Client)
* Crypt support (\a PICrypt, \a PIAuth)
\~russian \~russian
* Общение с консолью (\a PICout) * общение с консолью (\a PICout)
* Контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet) * контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* Байтовый массив (\a PIByteArray) * байтовый массив (\a PIByteArray)
* Сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON) * сериализация (\a PIChunkStream)
* Строка (\a PIConstChars, \a PIString, \a PIStringList) * строка (\a PIConstChars, \a PIString, \a PIStringList)
* Базовый объект (события и обработчики) (\a PIObject) * базовый объект (события и обработчики) (\a PIObject)
* Многопоточность * многопоточность
* поток (\a PIThread) * поток (\a PIThread)
* блокировки (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock) * блокировки (\a PIMutex, \a PISpinlock)
* исполнитель (\a PIThreadPoolExecutor, \a PIThreadPoolLoop) * исполнитель (\a PIThreadPoolExecutor)
* блокирующая очередь (\a PIBlockingDequeue) * блокирующая очередь (\a PIBlockingDequeue)
* таймер (\a PITimer) * таймер (\a PITimer)
* Тайлинговая консоль (с виджетами) (\a PIScreen) * тайлинговая консоль (с виджетами) (\a PIScreen)
* простой вывод строк * простой вывод строк
* скроллбар * скроллбар
* лист * лист
@@ -86,7 +76,7 @@
* прогрессбар * прогрессбар
* вывод PICout * вывод PICout
* текстовый ввод * текстовый ввод
* Устройства ввода/вывода * устройства ввода/вывода
* базовый класс (\a PIIODevice) * базовый класс (\a PIIODevice)
* файл (\a PIFile) * файл (\a PIFile)
* последовательный порт (\a PISerial) * последовательный порт (\a PISerial)
@@ -97,9 +87,8 @@
* сложное составное устройство (\a PIConnection) * сложное составное устройство (\a PIConnection)
* пиринговая сеть (\a PIPeer) * пиринговая сеть (\a PIPeer)
* диагностика качества связи (\a PIDiagnostics) * диагностика качества связи (\a PIDiagnostics)
* Поддержка библиотек времени выполнения * поддержка библиотек времени выполнения
* внешний процесс (\a PIProcess) * базовая функциональность (\a PILibrary)
* внешняя библиотека (\a PILibrary)
* плагин (\a PIPluginLoader) * плагин (\a PIPluginLoader)
* Математика * Математика
* комплексные числа * комплексные числа
@@ -111,14 +100,5 @@
* CRC контрольная сумма (\a PICRC) * CRC контрольная сумма (\a PICRC)
* преобразования Фурье (\a PIFFTW, \a PIFFT) * преобразования Фурье (\a PIFFTW, \a PIFFT)
* вычислитель выражений (\a PIEvaluator) * вычислитель выражений (\a PIEvaluator)
* Уровень приложения * парсер аргументов командной строки (\a PICLI)
* парсер аргументов командной строки (\a PICLI) * процесс (\a PIProcess)
* мониторинг ресурсов системы (\a PISystemMonitor)
* контроль одного экземпляра приложения (\a PISingleApplication)
* высокоуровневый лог (\a PILog)
* поддержка перевода (\a PITranslator)
* Машина состояний ([По стандарту](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* Высокоуровневый TCP клиент-сервер
* сервер (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* клиент (\a PIClientServer::Client)
* Поддержка шифрования (\a PICrypt, \a PIAuth)

View File

@@ -56,7 +56,7 @@ class MainClass: public PITimer {
public: public:
MainClass() {} MainClass() {}
protected: protected:
void tick(int delimiter) { void tick(void * data, int delimiter) {
piCout << "timer tick"; piCout << "timer tick";
// timer tick // timer tick
} }

View File

@@ -1 +1,2 @@
#include "pip.h" #include "pip.h"

View File

@@ -1 +0,0 @@
pip_tr --Compile -o pip_ru.btf pip_ru.ts

Binary file not shown.

View File

@@ -1,531 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru">
<context>
<name>PICLI</name>
<message>
<location filename="../libs/main/application/picli.cpp" line="120"/>
<source>Arguments overflow, &quot;%1&quot; ignored</source>
<translation>Переизбыток аргументов, &quot;%1&quot; проигнорирован</translation>
</message>
</context>
<context>
<name>PIDiag</name>
<message>
<location filename="../libs/main/io_utils/pidiagnostics.cpp" line="155"/>
<source>/s</source>
<translation>/сек</translation>
</message>
</context>
<context>
<name>PIFile</name>
<message>
<location filename="../libs/main/io_devices/pifile.cpp" line="300"/>
<source>Downsize is not supported yet :-(</source>
<translation>Уменьшение размера не поддерживается</translation>
</message>
</context>
<context>
<name>PICloud</name>
<message>
<location filename="../libs/cloud/picloudtcp.cpp" line="139"/>
<source>Invalid PICloud::TCP version!</source>
<translation>Неверная версия PICloud::TCP!</translation>
</message>
<message>
<location filename="../libs/cloud/picloudserver.cpp" line="230"/>
<source>Error: buffer overflow, drop %1 bytes</source>
<translation>Ошибка: переполнение буфера, отброшено %1 байт</translation>
</message>
<message>
<location filename="../libs/cloud/picloudserver.cpp" line="251"/>
<source>Warning: reject client with duplicated ID</source>
<translation>Предупреждение: отклонен клиент с дублирующимся ID</translation>
</message>
</context>
<context>
<name>PICrypt</name>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="187"/>
<source>internal error: bad hash size</source>
<translation>внутренняя ошибка: плохой размер хэша</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="35"/>
<source>Error while initialize sodium!</source>
<translation>Ошибка инициализации sodium!</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="190"/>
<source>invalid key size %1, should be %2, filled with zeros</source>
<translation>неверный размер ключа %1, должен быть %2, заполненный нулями</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="29"/>
<source>Warning: PICrypt is disabled, to enable install sodium library and rebuild pip</source>
<translation type="vanished">Предупреждение: PICrypt неактивен, для активации установите библиотеку sodium и пересоберите PIP</translation>
</message>
</context>
<context>
<name>PIBinLog</name>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="438"/>
<source>Read record error</source>
<translation>Ошибка чтения записи</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="434"/>
<source>End of BinLog file</source>
<translation>Конец BinLog файла</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="778"/>
<source>Error, can&apos;t open &quot;%1&quot;</source>
<translation>Ошибка, невозможно открыть &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="264"/>
<source>Creating directory &quot;%1&quot;</source>
<translation>Создание директории &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="787"/>
<source>Error, can&apos;t create &quot;%1&quot;</source>
<translation>Ошибка, невозможно создать &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="140"/>
<source>Error: File is null &quot;%1&quot;</source>
<translation>Ошибка, Файл пуст &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="791"/>
<source>Start join binlogs to &quot;%1&quot;</source>
<translation>Начало слияния логов в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="516"/>
<source>BinLogFile has too old verion</source>
<translation>BinLogFile очень старой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="515"/>
<source>BinLogFile has invalid version</source>
<translation>BinLogFile неверной версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="517"/>
<source>BinLogFile has too new version</source>
<translation>BinLogFile очень новой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="388"/>
<source>Can&apos;t find record with id = %1</source>
<translation>Невозможно найти запись с ID = %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="805"/>
<source>Error, can&apos;t write to file &quot;%1&quot;</source>
<translation>Ошибка, невозможно записать в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="126"/>
<source>Error: Can&apos;t open file &quot;%1&quot;: %2</source>
<translation>Ошибка: Невозможно открыть файл &quot;%1&quot;: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="149"/>
<source>Warning: Empty BinLog file &quot;%1&quot;</source>
<translation>Предупреждение: Пустой BinLog файл &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="827"/>
<source>Finish join binlogs, total time %1</source>
<translation>Завершение слияния логов, общее время %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="442"/>
<source>too small read buffer: %1, data size: %2</source>
<translation>слишком маленький буфер: %1, размер данных: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="133"/>
<source>Error: Can&apos;t write binlog file header &quot;%1&quot;</source>
<translation>Ошибка: Невозможно записать заголовок в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="321"/>
<source>Error: can`t write with id = 0! ID must be &gt; 0</source>
<translation>Ошибка: Невозможно записать с ID = 0! ID должен быть &gt; 0</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="497"/>
<source>BinLogFile signature is corrupted or invalid file</source>
<translation>Неверный заголовок BinLogFile, либо файл поврежден</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="297"/>
<source>Can&apos;t create new file, maybe path &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно путь &quot;%1&quot; неверен</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="288"/>
<source>Can&apos;t create new file, maybe LogDir &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно LogDir &quot;%1&quot; неверен</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="104"/>
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
</message>
</context>
<context>
<name>PIOpenCL</name>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="549"/>
<source>Error: empty range</source>
<translation>Ошибка: пустой диапазон</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="626"/>
<source>setArgValue invalid index %1</source>
<translation>setArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="656"/>
<source>bindArgValue invalid index %1</source>
<translation>bindArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="632"/>
<source>setArgValue set scalar to &quot;%1 %2&quot;</source>
<translation>setArgValue устанавливается скаляр в &quot;%1 %2&quot;</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="93"/>
<source>Error: OpenCL platforms not found!</source>
<translation>Ошибка: Платформы OpenCL не найдены!</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="662"/>
<source>bindArgValue set buffer to &quot;%1 %2&quot;</source>
<translation>bindArgValue устанавливается буфер в &quot;%1 %2&quot;</translation>
</message>
</context>
<context>
<name>PISerial</name>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="887"/>
<source>Read error: %1</source>
<translation>Ошибка чтения: %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="726"/>
<source>Unable to open &quot;%1&quot;: %2</source>
<translation>Невозможно открыть &quot;%1&quot;: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="467"/>
<source>Warning: Custom speed %1</source>
<translation>Предупреждение: Нестандартная скорость %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="695"/>
<source>Unable to find device &quot;%1&quot;</source>
<translation>Невозможно найти устройство &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="826"/>
<source>Can`t set attributes for &quot;%1&quot;</source>
<translation>Невозможно установить атрибуты для &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="792"/>
<source>Unable to set comm state for &quot;%1&quot;</source>
<translation>Невозможно установить comm state для &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="470"/>
<source>Warning: Unknown speed %1, using 115200</source>
<translation>Предупреждение: Неизвестная скорость %1, используется 115200</translation>
</message>
</context>
<context>
<name>PIString</name>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1787"/>
<source>B</source>
<translation>Б</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1807"/>
<source>EiB</source>
<translation>ЭиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1804"/>
<source>GiB</source>
<translation>ГиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1802"/>
<source>KiB</source>
<translation>КиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1803"/>
<source>MiB</source>
<translation>МиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1806"/>
<source>PiB</source>
<translation>ПиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1805"/>
<source>TiB</source>
<translation>ТиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1809"/>
<source>YiB</source>
<translation>ЙиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1808"/>
<source>ZiB</source>
<translation>ЗиБ</translation>
</message>
</context>
<context>
<name>PIThread</name>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="668"/>
<source>Warning, terminate!</source>
<translation>Предупреждение, прекращение потока!</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="781"/>
<source>Error: Can`t start new thread: %1</source>
<translation>Ошибка: Невозможно начать новый поток: %1</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="573"/>
<source>[PIThread &quot;%1&quot;] Warning, terminate on destructor!</source>
<translation>[PIThread &quot;%1&quot;] Предупреждение, прекращение в деструкторе!</translation>
</message>
</context>
<context>
<name>PIProcess</name>
<message>
<location filename="../libs/main/system/piprocess.cpp" line="200"/>
<source>&quot;CreateProcess&quot; error: %1</source>
<translation>Ошибка &quot;CreateProcess&quot;: %1</translation>
</message>
</context>
<context>
<name>PIVariant</name>
<message>
<location filename="../libs/main/types/pivariant.cpp" line="415"/>
<source>Can`t initialize PIVariant from unregistered type &quot;%1&quot;!</source>
<translation>Невозможно инициализировать PIVariant из незарегистрированного типа &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/types/pivariant.cpp" line="393"/>
<source>Can`t initialize PIVariant from unregistered typeID &quot;%1&quot;!</source>
<translation>Невозможно инициализировать PIVariant из незарегистрированного ID типа &quot;%1&quot;!</translation>
</message>
</context>
<context>
<name>PICompress</name>
<message>
<location filename="../libs/compress/picompress.cpp" line="63"/>
<source>Error: invalid input</source>
<translation>Ошибка: неверный вход</translation>
</message>
<message>
<location filename="../libs/compress/picompress.cpp" line="74"/>
<source>Error: invalid input or not enought memory</source>
<translation>Ошибка: неверный вход или недостаточно памяти</translation>
</message>
<message>
<location filename="../libs/compress/picompress.cpp" line="80"/>
<source>Warning: PICompress is disabled, to enable install zlib library and build pip_compress library</source>
<translation>Предупреждение: PICompress неактивен, для активации установите библиотеку zlib и пересоберите PIP</translation>
</message>
</context>
<context>
<name>PIEthernet</name>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1272"/>
<source>Can`t get interfaces: %1</source>
<translation>Невозможно получить интерфейсы: %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="942"/>
<source>Can`t accept new connection, %1</source>
<translation>Невозможно принять новое соединение, %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1135"/>
<source>Error allocating memory needed to call GetAdaptersInfo</source>
<translation>Ошибка выделения памяти для вызова GetAdaptersInfo</translation>
</message>
</context>
<context>
<name>PIIODevice</name>
<message>
<location filename="../libs/main/io_devices/piiodevice.cpp" line="226"/>
<source>Error: Device is running after destructor!</source>
<translation>Ошибка: Устройство в поточном выполнении после деструктора!</translation>
</message>
</context>
<context>
<name>PIIOString</name>
<message>
<location filename="../libs/main/io_devices/piiostring.cpp" line="54"/>
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
</message>
</context>
<context>
<name>PIConnection</name>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
<source>Error,</source>
<translation>Ошибка,</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="922"/>
<source>Null Device!</source>
<translation>Нет Устройства!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="913"/>
<source>No such device &quot;%1&quot;!</source>
<translation>Нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="903"/>
<source>No such full path &quot;%1&quot;!</source>
<translation>Нет полного пути &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="927"/>
<source>Device &quot;%1&quot; can`t write!</source>
<translation>Устройство &quot;%1&quot; не может писать!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="986"/>
<source>Error: can`t create device &quot;%1&quot;!</source>
<translation>Ошибка: Невозможно создать устройство &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="242"/>
<source>&quot;addFilter&quot; error: no such device &quot;%1&quot;!</source>
<translation>ошибка &quot;addFilter&quot;: нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="743"/>
<source>&quot;addSender&quot; error: no such device &quot;%1&quot;!</source>
<translation>ошибка &quot;addSender&quot;: нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
<source>names assigned to both devices and filters!</source>
<translation>имена назначены одновременно устройствам и фильтрам!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="512"/>
<source>&quot;addFilter&quot; error: no such device or filter &quot;%1&quot;!</source>
<translation>ошибка &quot;addFilter&quot;: нет устройства или фильтра &quot;%1&quot;!</translation>
</message>
</context>
<context>
<name>PISystemTime</name>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="343"/>
<source>fromSystemTime() Warning: null frequency</source>
<translation>fromSystemTime() Предупреждение: нулевая частота</translation>
</message>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="333"/>
<source>toSystemTime() Warning: invalid hertz: %1</source>
<translation>toSystemTime() Предупреждение: неверная частота: %1</translation>
</message>
</context>
<context>
<name>PIEthUtilBase</name>
<message>
<location filename="../libs/io_utils/piethutilbase.cpp" line="91"/>
<source>PICrypt wasn`t built!</source>
<translation>PICrypt не был собран!</translation>
</message>
</context>
<context>
<name>PIBaseTransfer</name>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="125"/>
<source>invalid CRC</source>
<translation>неверная CRC</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="219"/>
<source>restart receive</source>
<translation>перезапуск приема</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="176"/>
<source>invalid reply id</source>
<translation>неверный ID ответа</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="102"/>
<source>invalid packet signature</source>
<translation>неверная подпись пакета</translation>
</message>
</context>
<context>
<name>PIClientServer</name>
<message>
<location filename="../libs/client_server/piclientserver_server.cpp" line="39"/>
<source>ClientFactory returns nullptr!</source>
<translation>ClientFactory вернул nullptr!</translation>
</message>
<message>
<location filename="../libs/client_server/piclientserver_server.cpp" line="33"/>
<source>Server::newConnection overflow clients count</source>
<translation>Server::newConnection переполнение количества клиентов</translation>
</message>
</context>
<context>
<name>PIStateMachine</name>
<message>
<location filename="../libs/main/state_machine/pistatemachine_state.cpp" line="111"/>
<source>Error: &quot;%1&quot; no initial state!</source>
<translation>Ошибка: &quot;%1&quot; без стартового состояния!</translation>
</message>
</context>
<context>
<name>PIStreamPacker</name>
<message>
<location filename="../libs/io_utils/pistreampacker.cpp" line="168"/>
<source>Warning! Not recommended to use with non-reliable device</source>
<translation>Предупреждение! Не рекомендуется использовать с ненадежными устройствами</translation>
</message>
</context>
<context>
<name>PISystemMonitor</name>
<message>
<location filename="../libs/main/application/pisystemmonitor.cpp" line="111"/>
<source>Can`t find process with ID = %1!</source>
<translation>Невозможно найти процесс с ID = %1!</translation>
</message>
<message>
<location filename="../libs/main/application/pisystemmonitor.cpp" line="118"/>
<source>Can`t open process with ID = %1, %2!</source>
<translation>Невозможно открыть процесс с ID = %1, %2!</translation>
</message>
</context>
</TS>

View File

@@ -1 +0,0 @@
pip_tr --Parse -r -l ru -o pip_ru.ts ../libs

View File

@@ -1,53 +0,0 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_client.h"
#include "piclientserver_server.h"
#include "piethernet.h"
void PIClientServer::ServerClient::createForServer(Server * parent, PIEthernet * tcp_) {
tcp = tcp_;
tcp->setParameter(PIEthernet::KeepConnection, false);
init();
CONNECTL(tcp, disconnected, ([this, parent](bool) { parent->clientDisconnected(this); }));
}
PIClientServer::Client::Client() {
tcp = new PIEthernet(PIEthernet::TCP_Client);
tcp->setParameter(PIEthernet::KeepConnection, true);
own_tcp = true;
init();
}
PIClientServer::Client::~Client() {
if (tcp) tcp->setDebug(false);
close();
stopAndWait();
}
void PIClientServer::Client::connect(PINetworkAddress addr) {
if (!tcp || !own_tcp) return;
close();
tcp->connect(addr, true);
tcp->startThreadedRead();
}

View File

@@ -1,117 +0,0 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_client_base.h"
#include "piethernet.h"
#include "piliterals_time.h"
PIClientServer::ClientBase::ClientBase() {}
PIClientServer::ClientBase::~ClientBase() {
close();
stopAndWait();
if (own_tcp) piDeleteSafety(tcp);
piDeleteSafety(diag);
}
void PIClientServer::ClientBase::close() {
if (!tcp) return;
can_write = false;
tcp->stop();
stream.clear();
}
void PIClientServer::ClientBase::stopAndWait() {
if (!tcp) return;
tcp->stopAndWait(10_s);
if (tcp->isThreadedRead()) tcp->terminateThreadedRead();
tcp->close();
stream.clear();
}
int PIClientServer::ClientBase::write(const void * d, const size_t s) {
if (!tcp) return -1;
if (!can_write) return 0;
PIMutexLocker guard(write_mutex);
// piCout << "... send ...";
stream.send(PIByteArray(d, s));
// piCout << "... send ok";
return s;
}
void PIClientServer::ClientBase::enableDiagnostics() {
if (diag) return;
diag = new PIDiagnostics();
}
PIDiagnostics::State PIClientServer::ClientBase::diagnostics() const {
if (!diag) return {};
return diag->state();
}
int PIClientServer::ClientBase::receivePacketProgress() const {
return stream.receivePacketProgress();
}
void PIClientServer::ClientBase::init() {
if (!tcp) return;
CONNECTL(&stream, sendRequest, [this](const PIByteArray & ba) {
if (!can_write) return;
tcp->send(ba);
if (diag) diag->sended(ba.size_s());
// piMSleep(1);
});
CONNECTL(&stream, packetReceiveEvent, [this](PIByteArray & ba) { readed(ba); });
CONNECTL(&stream, startPacketReceive, [this](int size) { receivePacketStart(size); });
CONNECTL(&stream, endPacketReceive, [this]() { receivePacketEnd(); });
CONNECTL(tcp, threadedReadEvent, [this](const uchar * readed, ssize_t size) {
if (!can_write) return;
stream.received(readed, size);
if (diag) diag->received(size);
});
CONNECTL(tcp, connected, [this]() {
can_write = true;
// piCout << "Connected";
connected();
});
CONNECTL(tcp, disconnected, [this](bool) {
can_write = false;
stream.clear();
// piCout << "Disconnected";
disconnected();
});
}
void PIClientServer::ClientBase::destroy() {
write_mutex.lock();
close();
piDeleteSafety(tcp);
write_mutex.unlock();
// piCout << "Destroyed";
}

View File

@@ -1,143 +0,0 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_server.h"
#include "piclientserver_client.h"
#include "piethernet.h"
#include "pitranslator.h"
PIClientServer::Server::Server() {
tcp_server = new PIEthernet(PIEthernet::TCP_Server);
clean_thread = new PIThread();
client_factory = [] { return new ServerClient(); };
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
PIMutexLocker guard(clients_mutex);
if (clients.size_s() >= max_clients) {
piCout << "Server::newConnection overflow clients count"_tr("PIClientServer");
delete c;
return;
}
auto sc = client_factory();
if (!sc) {
piCout << "ClientFactory returns nullptr!"_tr("PIClientServer");
return;
}
sc->createForServer(this, c);
newClient(sc);
});
clean_thread->start([this]() {
clean_notifier.wait();
PIVector<ServerClient *> to_delete;
clients_mutex.lock();
for (auto c: clients) {
const PIEthernet * eth = c->getTCP();
if (!eth) continue;
if (eth->isConnected()) continue;
c->can_write = false;
to_delete << c;
}
for (auto c: to_delete)
clients.removeOne(c);
clients_mutex.unlock();
for (auto c: to_delete) {
c->aboutDelete();
c->destroy();
delete c;
}
});
}
PIClientServer::Server::~Server() {
clean_thread->stop();
clean_notifier.notify();
clean_thread->waitForFinish();
piDeleteSafety(clean_thread);
stopServer();
for (auto c: clients) {
c->aboutDelete();
c->destroy();
delete c;
}
piDeleteSafety(tcp_server);
}
void PIClientServer::Server::listen(PINetworkAddress addr) {
if (!tcp_server) return;
stopServer();
is_closing = false;
tcp_server->listen(addr, true);
// piCout << "Listen on" << addr.toString();
}
void PIClientServer::Server::closeAll() {
clients_mutex.lock();
for (auto c: clients) {
c->aboutDelete();
c->destroy();
delete c;
}
clients.clear();
clients_mutex.unlock();
}
void PIClientServer::Server::setMaxClients(int new_max_clients) {
max_clients = new_max_clients;
}
int PIClientServer::Server::clientsCount() const {
PIMutexLocker guard(clients_mutex);
return clients.size_s();
}
void PIClientServer::Server::forEachClient(std::function<void(ServerClient *)> func) {
PIMutexLocker guard(clients_mutex);
for (auto * c: clients) {
func(c);
if (is_closing) break;
}
}
void PIClientServer::Server::stopServer() {
if (!tcp_server) return;
is_closing = true;
tcp_server->stopThreadedListen();
tcp_server->stopAndWait();
}
void PIClientServer::Server::newClient(ServerClient * c) {
clients << c;
c->setConfiguration(configuration());
c->tcp->startThreadedRead();
c->connected();
}
void PIClientServer::Server::clientDisconnected(ServerClient * c) {
clean_notifier.notify();
}

View File

@@ -1,7 +1,7 @@
#include "picloudbase.h" #include "picloudbase.h"
PICloudBase::PICloudBase(): eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) { PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) {
eth.setDebug(false); eth.setDebug(false);
} }

View File

@@ -1,192 +1,178 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Client PICloud Client
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picloudclient.h" #include "picloudclient.h"
#include "picloudtcp.h"
#include "picloudtcp.h"
#include "pitranslator.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode), PICloudBase() {
tcp.setRole(PICloud::TCP::Client);
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() { setName("cloud_client");
tcp.setRole(PICloud::TCP::Client); is_connected = false;
setThreadedReadBufferSize(eth.threadedReadBufferSize()); is_deleted = false;
setName("cloud_client"); // setReopenEnabled(false);
is_connected = false; CONNECTL(&eth, connected, [this](){opened_ = true; tcp.sendStart();});
is_deleted = false; CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
// setReopenEnabled(false); CONNECTL(&eth, disconnected, [this](bool){
CONNECTL(&eth, connected, [this]() { if (is_deleted) return;
opened_ = true; bool need_disconn = is_connected;
tcp.sendStart(); //piCoutObj << "eth disconnected";
}); static_cast<PIThread*>(&eth)->stop();
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); opened_ = false;
CONNECTL(&eth, disconnected, [this](bool) { internalDisconnect();
if (is_deleted) return; if (need_disconn)
bool need_disconn = is_connected; disconnected();
// piCoutObj << "eth disconnected"; //piCoutObj << "eth disconnected done";
eth.stop(); });
opened_ = false; }
internalDisconnect();
if (need_disconn) disconnected();
// piCoutObj << "eth disconnected done"; PICloudClient::~PICloudClient() {
}); //piCoutObj << "~PICloudClient()";
} PIThread::stop();
//eth.close();
//if (is_connected) disconnected();
PICloudClient::~PICloudClient() { close();
// piCoutObj << "~PICloudClient() ..." << this; //piCoutObj << "~PICloudClient() closed";
is_deleted = true; internalDisconnect();
stopAndWait(); // stop(false);
close(); is_deleted = true;
internalDisconnect(); internalDisconnect();
// piCoutObj << "~PICloudClient() done" << this; //piCoutObj << "~PICloudClient() done";
} }
void PICloudClient::setServerName(const PIString & server_name) { void PICloudClient::setServerName(const PIString & server_name) {
setName("cloud_client__" + server_name); setName("cloud_client__" + server_name);
tcp.setServerName(server_name); tcp.setServerName(server_name);
} }
void PICloudClient::setKeepConnection(bool on) { void PICloudClient::setKeepConnection(bool on) {
eth.setParameter(PIEthernet::KeepConnection, on); eth.setParameter(PIEthernet::KeepConnection, on);
} }
void PICloudClient::interrupt() { bool PICloudClient::openDevice() {
cond_buff.notifyOne(); //piCoutObj << "open";// << path();
cond_connect.notifyOne(); bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
eth.interrupt(); if (op) {
} mutex_connect.lock();
eth.startThreadedRead();
//piCoutObj << "connecting...";
bool PICloudClient::openDevice() { bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout());
// piCoutObj << "open";// << path(); //piCoutObj << "conn_ok" << conn_ok << is_connected;
bool op = eth.connect(PINetworkAddress::resolve(path()), false); mutex_connect.unlock();
if (op) { if (!conn_ok) {
mutex_connect.lock(); mutex_connect.lock();
eth.startThreadedRead(); eth.stop();
// piCoutObj << "connecting..."; eth.close();
bool conn_ok = cond_connect.waitFor(mutex_connect, eth.readTimeout()); mutex_connect.unlock();
// piCoutObj << "conn_ok" << conn_ok << is_connected; }
mutex_connect.unlock(); return is_connected;
if (!conn_ok) { } else {
mutex_connect.lock(); //eth.close();
eth.stopAndWait(); return false;
eth.close(); }
mutex_connect.unlock(); }
}
return is_connected;
} else { bool PICloudClient::closeDevice() {
// eth.close(); //PIThread::stop();
return false; if (is_connected) {
} internalDisconnect();
} }
eth.stop();
eth.close();
bool PICloudClient::closeDevice() { return true;
// PIThread::stop(); }
if (is_connected) {
internalDisconnect();
} int PICloudClient::readDevice(void * read_to, int max_size) {
eth.stopAndWait(); if (is_deleted) return -1;
eth.close(); //piCoutObj << "readDevice";
return true; if (!is_connected && eth.isClosed()) openDevice();
} int sz = -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { if (is_connected) {
if (is_deleted || max_size <= 0) return -1; sz = piMini(max_size, buff.size());
// piCoutObj << "readDevice ..."; memcpy(read_to, buff.data(), sz);
if (!is_connected && eth.isClosed()) openDevice(); buff.remove(0, sz);
ssize_t sz = -1; }
mutex_buff.lock(); mutex_buff.unlock();
if (is_connected) { if (!is_connected) opened_ = false;
if (buff.isEmpty()) { //piCoutObj << "readDevice done" << sz;
sz = 0; return sz;
} else { }
sz = piMin<ssize_t>(max_size, buff.size_s());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz); int PICloudClient::writeDevice(const void * data, int size) {
} if (is_deleted) return -1;
if (sz == 0) cond_buff.wait(mutex_buff); // piCoutObj << "writeDevice";
} return tcp.sendData(PIByteArray(data, size));
mutex_buff.unlock(); }
if (!is_connected) opened_ = false;
// piCoutObj << "readDevice done" << sz;
return sz; void PICloudClient::internalDisconnect() {
} is_connected = false;
cond_buff.notifyOne();
cond_connect.notifyOne();
ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { streampacker.clear();
if (is_deleted || !is_connected) return -1; buff.clear();
// piCoutObj << "writeDevice" << size; }
return tcp.sendData(PIByteArray(data, size));
}
void PICloudClient::_readed(PIByteArray & ba) {
if (is_deleted) return;
void PICloudClient::internalDisconnect() { PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
// piCoutObj << "internalDisconnect"; //piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second;
is_connected = false; if (hdr.second == tcp.role()) {
cond_buff.notifyOne(); switch (hdr.first) {
cond_connect.notifyOne(); case PICloud::TCP::Connect:
streampacker.clear(); if (tcp.parseConnect(ba) == 1) {
buff.clear(); mutex_connect.lock();
} is_connected = true;
mutex_connect.unlock();
cond_connect.notifyOne();
void PICloudClient::_readed(PIByteArray & ba) { connected();
if (is_deleted) return; }
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba); break;
// piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second; case PICloud::TCP::Disconnect:
if (hdr.second == tcp.role()) { static_cast<PIThread*>(&eth)->stop();
switch (hdr.first) { opened_ = false;
case PICloud::TCP::Connect: eth.close();
if (tcp.parseConnect(ba) == 1) { break;
mutex_connect.lock(); case PICloud::TCP::Data:
is_connected = true; if (is_connected) {
mutex_connect.unlock(); mutex_buff.lock();
cond_connect.notifyOne(); buff.append(ba);
connected(); mutex_buff.unlock();
} cond_buff.notifyOne();
break; }
case PICloud::TCP::Disconnect: break;
eth.stop(); default:
opened_ = false; break;
eth.close(); }
break; //piCoutObj << "readed" << ba.toHex();
case PICloud::TCP::Data: }
if (is_connected) { while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
mutex_buff.lock(); //piCoutObj << "_readed done";
if (buff.size_s() > threadedReadBufferSize()) { }
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
mutex_buff.unlock();
return;
}
buff.append(ba);
mutex_buff.unlock();
cond_buff.notifyOne();
}
break;
default: break;
}
// piCoutObj << "readed" << ba.toHex();
}
// piCoutObj << "_readed done";
}

View File

@@ -1,301 +1,238 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Server PICloud Server
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picloudserver.h" #include "picloudserver.h"
#include "piliterals_time.h"
#include "pitranslator.h" PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode), PICloudBase() {
PIString server_name = "PCS_" + PIString::fromNumber(randomi()%1000);
tcp.setRole(PICloud::TCP::Server);
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() { tcp.setServerName(server_name);
PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000); setName("cloud_server__" + server_name);
tcp.setRole(PICloud::TCP::Server); CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
tcp.setServerName(server_name); CONNECTL(&eth, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();});
setName("cloud_server__" + server_name); CONNECTL(&eth, disconnected, [this](bool){
is_deleted = false; piCoutObj << "disconnected";
eth.setReopenEnabled(false); static_cast<PIThread*>(&eth)->stop();
setThreadedReadBufferSize(eth.threadedReadBufferSize()); opened_ = false;
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); ping_timer.stop(false);
CONNECTL(&eth, connected, [this]() { piMSleep(100);
open_mutex.lock(); });
opened_ = true; CONNECTL(&ping_timer, tickEvent, [this] (void *, int){
cvar.notifyOne(); if (eth.isConnected()) tcp.sendPing();
open_mutex.unlock(); });
piCoutObj << "connected"; }
tcp.sendStart();
});
CONNECTL(&eth, disconnected, [this](bool) { PICloudServer::~PICloudServer() {
if (is_deleted) return; stop();
piCoutObj << "disconnected"; close();
clients_mutex.lock(); }
for (auto c: clients_) {
c->is_connected = false;
c->close(); void PICloudServer::setServerName(const PIString & server_name) {
} setName("cloud_server__" + server_name);
removed_clients_.append(clients_); tcp.setServerName(server_name);
clients_.clear(); }
index_clients.clear();
clients_mutex.unlock();
open_mutex.lock(); PIVector<PICloudServer::Client *> PICloudServer::clients() const {
opened_ = false; PIMutexLocker _ml(clients_mutex);
cvar.notifyOne(); return clients_;
open_mutex.unlock(); }
ping_timer.stop();
});
ping_timer.setSlot([this]() { bool PICloudServer::openDevice() {
if (eth.isConnected()) tcp.sendPing(); //piCout << "PICloudServer open device" << path();
}); bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
} if (op) {
eth.startThreadedRead();
ping_timer.start(5000);
PICloudServer::~PICloudServer() { return true;
// piCoutObj << "~PICloudServer ..." << this; }
is_deleted = true; ping_timer.stop(false);
stop(); eth.close();
close(); return false;
waitThreadedReadFinished(); }
// piCout << "wait";
while (removed_clients_.isNotEmpty()) {
Client * c = removed_clients_.take_back(); bool PICloudServer::closeDevice() {
delete c; eth.stop();
} ping_timer.stop(false);
// piCoutObj << "~PICloudServer done" << this; clients_mutex.lock();
} for (auto c : clients_) {
c->close();
c->stop();
void PICloudServer::setServerName(const PIString & server_name) { }
setName("cloud_server__" + server_name); clients_mutex.unlock();
tcp.setServerName(server_name); eth.close();
} for (auto c : clients_)
delete c;
return true;
PIVector<PICloudServer::Client *> PICloudServer::clients() const { }
PIMutexLocker _ml(clients_mutex);
return clients_;
} int PICloudServer::readDevice(void * read_to, int max_size) {
//piCoutObj << "readDevice";
if (!opened_) openDevice();
bool PICloudServer::openDevice() { else piMSleep(eth.readTimeout());
piCoutObj << "open device" << path(); return -1;
if (is_deleted) return false; }
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) {
eth.startThreadedRead(); int PICloudServer::writeDevice(const void * data, int max_size) {
ping_timer.start(5_s); //piCoutObj << "writeDevice";
return true; return -1;
} else { }
ping_timer.stop();
eth.close();
return false; void PICloudServer::clientDisconnect(uint client_id) {
} tcp.sendDisconnected(client_id);
} }
bool PICloudServer::closeDevice() { int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
// piCoutObj << "closeDevice" << this; return tcp.sendData(data, client_id);
eth.stopAndWait(); }
ping_timer.stop();
eth.close();
cvar.notifyOne(); PICloudServer::Client::Client(PICloudServer * srv, uint id) : server(srv), client_id(id) {
clients_mutex.lock(); setMode(PIIODevice::ReadWrite);
for (auto c: clients_) { setReopenEnabled(false);
c->is_connected = false; is_connected = true;
c->close(); }
}
removed_clients_.append(clients_);
clients_.clear(); PICloudServer::Client::~Client() {
index_clients.clear(); if (is_connected) {
clients_mutex.unlock(); is_connected = false;
return true; cond_buff.notifyOne();
} }
close();
stop();
ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) { }
if (is_deleted) return -1;
// piCoutObj << "readDevice";
open_mutex.lock(); bool PICloudServer::Client::openDevice() {
if (isOpened()) cvar.wait(open_mutex); return is_connected;
open_mutex.unlock(); }
// piCoutObj << "opened_ = " << opened_;
// else piMSleep(eth.readTimeout());
return -1; bool PICloudServer::Client::closeDevice() {
} PIThread::stop(false);
if (is_connected) {
server->clientDisconnect(client_id);
ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) { is_connected = false;
// piCoutObj << "writeDevice"; }
return -1; cond_buff.notifyOne();
} return true;
}
void PICloudServer::interrupt() {
eth.interrupt(); int PICloudServer::Client::readDevice(void * read_to, int max_size) {
cvar.notifyOne(); if (!is_connected) return -1;
} int sz = -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
void PICloudServer::clientDisconnect(uint client_id) { if (is_connected) {
tcp.sendDisconnected(client_id); sz = piMini(max_size, buff.size());
} memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
}
int PICloudServer::sendData(const PIByteArray & data, uint client_id) { mutex_buff.unlock();
if (!opened_) return -1; return sz;
return tcp.sendData(data, client_id); }
}
int PICloudServer::Client::writeDevice(const void * data, int size) {
PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client_id(id) { return server->sendData(PIByteArray(data, size), client_id);
setMode(PIIODevice::ReadWrite); }
setReopenEnabled(false);
setThreadedReadBufferSize(server->threadedReadBufferSize());
is_connected = true; void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
} if (!is_connected) return;
mutex_buff.lock();
buff.append(ba);
PICloudServer::Client::~Client() { cond_buff.notifyOne();
// piCoutObj << "~PICloudServer::Client..." << this; mutex_buff.unlock();
close(); while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
stopAndWait(10_s); }
// piCoutObj << "~PICloudServer::Client done" << this;
}
void PICloudServer::_readed(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
bool PICloudServer::Client::openDevice() { if (hdr.second == tcp.role()) {
return is_connected; switch (hdr.first) {
} case PICloud::TCP::Connect: {
uint id = tcp.parseConnect(ba);
clients_mutex.lock();
bool PICloudServer::Client::closeDevice() { Client * oc = index_clients.value(id, nullptr);
// piCoutObj << "closeDevice" << this; clients_mutex.unlock();
if (is_connected) { if (oc) {
server->clientDisconnect(client_id); tcp.sendDisconnected(id);
is_connected = false; } else {
} //piCoutObj << "new Client" << id;
cond_buff.notifyOne(); Client * c = new Client(this, id);
return true; CONNECTU(c, deleted, this, clientDeleted);
} clients_mutex.lock();
clients_ << c;
index_clients.insert(id, c);
ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) { clients_mutex.unlock();
if (!is_connected) return -1; newConnection(c);
ssize_t sz = -1; }
mutex_buff.lock(); } break;
if (is_connected) { case PICloud::TCP::Disconnect: {
if (buff.isEmpty()) { uint id = tcp.parseDisconnect(ba);
sz = 0; //piCoutObj << "remove Client" << id;
} else { clients_mutex.lock();
sz = piMini(max_size, buff.size()); Client * oc = index_clients.value(id, nullptr);
memcpy(read_to, buff.data(), sz); clients_mutex.unlock();
buff.remove(0, sz); if (oc) {
} oc->is_connected = false;
if (sz == 0) cond_buff.wait(mutex_buff); oc->close();
} }
mutex_buff.unlock(); } break;
return sz; case PICloud::TCP::Data: {
} PIPair<uint, PIByteArray> d = tcp.parseDataServer(ba);
clients_mutex.lock();
Client * oc = index_clients.value(d.first, nullptr);
ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) { clients_mutex.unlock();
if (!is_connected) return -1; //piCoutObj << "data for" << d.first << d.second.toHex();
return server->sendData(PIByteArray(data, size), client_id); if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} } break;
default: break;
}
void PICloudServer::Client::interrupt() { }
cond_buff.notifyOne(); }
}
void PICloudServer::clientDeleted(PIObject * o) {
void PICloudServer::Client::pushBuffer(const PIByteArray & ba) { PICloudServer::Client * c = (PICloudServer::Client*)o;
if (!is_connected) return; clients_mutex.lock();
mutex_buff.lock(); clients_.removeOne(c);
if (buff.size_s() > threadedReadBufferSize()) { auto it = index_clients.makeIterator();
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size()); while (it.hasNext()) {
mutex_buff.unlock(); it.next();
return; if (it.value() == c) {
} index_clients.remove(it.key());
buff.append(ba); break;
cond_buff.notifyOne(); }
mutex_buff.unlock(); }
} clients_mutex.unlock();
}
void PICloudServer::_readed(PIByteArray & ba) {
if (is_deleted) return;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect: {
uint id = tcp.parseConnect(ba);
clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock();
if (oc) {
piCoutObj << "Warning: reject client with duplicated ID"_tr("PICloud");
tcp.sendDisconnected(id);
} else {
Client * c = new Client(this, id);
// piCoutObj << "new Client" << id << c;
CONNECT1(void, PIObject *, c, deleted, this, clientDeleted);
clients_mutex.lock();
clients_ << c;
index_clients.insert(id, c);
clients_mutex.unlock();
newConnection(c);
}
} break;
case PICloud::TCP::Disconnect: {
uint id = tcp.parseDisconnect(ba);
// piCoutObj << "Close on logic";
clients_mutex.lock();
Client * oc = index_clients.take(id, nullptr);
clients_.removeOne(oc);
clients_mutex.unlock();
if (oc) {
oc->stopAndWait();
oc->is_connected = false;
oc->close();
removed_clients_ << oc;
// delete oc;
}
} break;
case PICloud::TCP::Data: {
PIPair<uint, PIByteArray> d = tcp.parseDataServer(ba);
clients_mutex.lock();
Client * oc = index_clients.value(d.first, nullptr);
clients_mutex.unlock();
// piCoutObj << "data for" << d.first << d.second.size();
if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} break;
default: break;
}
}
}
void PICloudServer::clientDeleted(PIObject * o) {
PICloudServer::Client * c = (PICloudServer::Client *)o;
// piCoutObj << "clientDeleted" << c;
clients_mutex.lock();
clients_.removeOne(c);
removed_clients_.removeAll(c);
index_clients.removeWhere([c](uint, Client * v) { return v == c; });
clients_mutex.unlock();
}

View File

@@ -1,185 +1,181 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud TCP transport PICloud TCP transport
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picloudtcp.h" #include "picloudtcp.h"
#include "picrypt.h"
#include "pichunkstream.h" #include "pichunkstream.h"
#include "picrypt.h" #include "piethernet.h"
#include "piethernet.h" #include "pistreampacker.h"
#include "pistreampacker.h"
#include "pitranslator.h"
const char hash_cloud_key[] = "_picloud_";
const char hash_cloud_key[] = "_picloud_";
PICloud::TCP::Header::Header() {
version = Version_2;
PICloud::TCP::Header::Header() { }
version = Version_2;
}
PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) {
streampacker->setMaxPacketSize(63*1024);
PICloud::TCP::TCP(PIStreamPacker * s): streampacker(s) { }
streampacker->setMaxPacketSize(63 * 1024);
} void PICloud::TCP::setRole(PICloud::TCP::Role r) {
header.role = r;
void PICloud::TCP::setRole(PICloud::TCP::Role r) { }
header.role = r;
}
void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_;
void PICloud::TCP::setServerName(const PIString & server_name_) { suuid = PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
server_name = server_name_; }
suuid =
PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
} PIString PICloud::TCP::serverName() const {
return server_name;
}
PIString PICloud::TCP::serverName() const {
return server_name;
} void PICloud::TCP::sendStart() {
//piCout << "sendStart";
if (suuid.size() != PICrypt::sizeHash()) {
void PICloud::TCP::sendStart() { piCout << "PICloud ERROR, server not set, invoke setServerName first";
// piCout << "sendStart"; return;
if (suuid.size() != PICrypt::sizeHash()) { }
piCout << "PICloud ERROR, server not set, invoke setServerName first"; header.type = PICloud::TCP::Connect;
return; PIByteArray ba;
} ba << header;
header.type = PICloud::TCP::Connect; ba.append(suuid);
PIByteArray ba; //mutex_send.lock();
ba << header; streampacker->send(ba);
ba.append(suuid); //mutex_send.unlock();
// mutex_send.lock(); }
streampacker->send(ba);
// mutex_send.unlock();
} void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect;
PIByteArray ba;
void PICloud::TCP::sendConnected(uint client_id) { ba << header << client_id;
header.type = PICloud::TCP::Connect; // mutex_send.lock();
PIByteArray ba; streampacker->send(ba);
ba << header << client_id; // mutex_send.unlock();
// mutex_send.lock(); }
streampacker->send(ba);
// mutex_send.unlock();
} void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect;
PIByteArray ba;
void PICloud::TCP::sendDisconnected(uint client_id) { ba << header << client_id;
header.type = PICloud::TCP::Disconnect; // mutex_send.lock();
PIByteArray ba; streampacker->send(ba);
ba << header << client_id; // mutex_send.unlock();
// mutex_send.lock(); }
streampacker->send(ba);
// mutex_send.unlock();
} int PICloud::TCP::sendData(const PIByteArray & data) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
int PICloud::TCP::sendData(const PIByteArray & data) { ba << header;
header.type = PICloud::TCP::Data; ba.append(data);
PIByteArray ba; // piCout << "[PICloud::TCP] sendData" << ba.toHex();
ba << header; mutex_send.lock();
ba.append(data); streampacker->send(ba);
// piCout << "[PICloud::TCP] sendData" << ba.toHex(); mutex_send.unlock();
mutex_send.lock(); return data.size_s();
streampacker->send(ba); }
mutex_send.unlock();
return data.size_s();
} int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) { ba << header << client_id;
header.type = PICloud::TCP::Data; ba.append(data);
PIByteArray ba; mutex_send.lock();
ba << header << client_id; streampacker->send(ba);
ba.append(data); mutex_send.unlock();
mutex_send.lock(); return data.size_s();
streampacker->send(ba); }
mutex_send.unlock();
return data.size_s();
} void PICloud::TCP::sendPing() {
header.type = PICloud::TCP::Ping;
PIByteArray ba;
void PICloud::TCP::sendPing() { ba << header;
header.type = PICloud::TCP::Ping; ba.append(suuid);
PIByteArray ba; mutex_send.lock();
ba << header; streampacker->send(ba);
ba.append(suuid); mutex_send.unlock();
mutex_send.lock(); }
streampacker->send(ba);
mutex_send.unlock();
} PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret;
ret.first = InvalidType;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) { ret.second = InvalidRole;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret; if (ba.size() < sizeof(Header)) return ret;
ret.first = InvalidType; PICloud::TCP::Header hdr;
ret.second = InvalidRole; ba >> hdr;
if (ba.size() < sizeof(Header)) return ret; if (hdr.version != header.version) {
PICloud::TCP::Header hdr; piCout << "[PICloud]" << "invalid PICloud::TCP version!";
ba >> hdr; return ret;
if (hdr.version != header.version) { }
piCout << "[PICloud]" ret.first = (Type)hdr.type;
<< "Invalid PICloud::TCP version!"_tr("PICloud"); ret.second = (Role)hdr.role;
return ret; return ret;
} }
ret.first = (Type)hdr.type;
ret.second = (Role)hdr.role;
return ret; bool PICloud::TCP::canParseData(PIByteArray & ba) {
} return header.role == Client;
}
bool PICloud::TCP::canParseData(PIByteArray & ba) {
return header.role == Client; PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) {
} PIPair<uint, PIByteArray> ret;
ret.first = 0;
if (header.role == Server) {
PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) { ba >> ret.first;
PIPair<uint, PIByteArray> ret; ret.second.swap(ba);
ret.first = 0; }
if (header.role == Server) { return ret;
ba >> ret.first; }
ret.second.swap(ba);
}
return ret; PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
} if (ba.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, invalid server uuid";
return PIByteArray();
PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) { } else {
if (ba.size() != PICrypt::sizeHash()) { return ba;
piCout << "PICloud ERROR, invalid server uuid"; }
return PIByteArray(); }
} else {
return ba;
} uint PICloud::TCP::parseConnect(PIByteArray & ba) {
} uint ret;
ba >> ret;
return ret;
uint PICloud::TCP::parseConnect(PIByteArray & ba) { }
uint ret = 0;
ba >> ret;
return ret; uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
} uint ret;
ba >> ret;
return ret;
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) { }
uint ret = 0;
ba >> ret;
return ret;
}

View File

@@ -1,83 +1,76 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Compress class using zlib Compress class using zlib
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picompress.h" #include "picompress.h"
#ifdef PIP_COMPRESS
#include "pitranslator.h" # ifdef ESP_PLATFORM
#ifdef PIP_COMPRESS # include "esp32/rom/miniz.h"
# ifdef ESP_PLATFORM # define compress2 mz_compress2
# include "esp32/rom/miniz.h" # define Z_OK MZ_OK
# define compress2 mz_compress2 # define uncompress mz_uncompress
# define Z_OK MZ_OK # else
# define uncompress mz_uncompress # include <zlib.h>
# else # endif
# include <zlib.h> #endif
# endif
#endif
PIByteArray piCompress(const PIByteArray & ba, int level) {
#ifdef PIP_COMPRESS
PIByteArray piCompress(const PIByteArray & ba, int level) { PIByteArray zba;
#ifdef PIP_COMPRESS zba.resize(ba.size() + 128);
PIByteArray zba; int ret = 0;
zba.resize(ba.size() + 128); ulong sz = zba.size();
int ret = 0; ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
ulong sz = zba.size(); if (ret != Z_OK) {
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level); piCout << "[PICompress]" << "Error: invalid input or not enought memory";
if (ret != Z_OK) { return ba;
piCout << "[PICompress]" }
<< "Error: invalid input or not enought memory"_tr("PICompress"); zba.resize(sz);
return ba; zba << ullong(ba.size());
} return zba;
zba.resize(sz); #else
zba << ullong(ba.size()); piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
return zba; #endif
#else return ba;
piCout << "[PICompress]" }
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif
return ba; PIByteArray piDecompress(const PIByteArray & zba) {
} #ifdef PIP_COMPRESS
ullong sz;
if (zba.size() < sizeof(ullong)) {
PIByteArray piDecompress(const PIByteArray & zba) { piCout << "[PICompress]" << "Error: invalid input";
#ifdef PIP_COMPRESS return zba;
ullong sz = 0; }
if (zba.size() < sizeof(ullong)) { PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
piCout << "[PICompress]" ba >> sz;
<< "Error: invalid input"_tr("PICompress"); ba.resize(sz);
return zba; int ret = 0;
} ulong s = sz;
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong)); ret = uncompress(ba.data(), &s, zba.data(), zba.size());
ba >> sz; if (ret != Z_OK) {
ba.resize(sz); piCout << "[PICompress]" << "Error: invalid input or not enought memory";
int ret = 0; return zba;
ulong s = sz; }
ret = uncompress(ba.data(), &s, zba.data(), zba.size()); return ba;
if (ret != Z_OK) { #else
piCout << "[PICompress]" piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
<< "Error: invalid input or not enought memory"_tr("PICompress"); #endif
return zba; return zba;
} }
return ba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif
return zba;
}

View File

@@ -1,38 +1,34 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Console output/input Console output/input
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreen.h" #include "piscreen.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piliterals_time.h"
// clang-format off
#ifndef WINDOWS #ifndef WINDOWS
# include <fcntl.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
# include <fcntl.h>
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE # ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
# endif # endif
#endif #endif
// clang-format on
using namespace PIScreenTypes; using namespace PIScreenTypes;
@@ -55,26 +51,14 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
PIScreen::SystemConsole::SystemConsole() { PIScreen::SystemConsole::SystemConsole() {
width = height = pwidth = pheight = 0; width = height = pwidth = pheight = 0;
mouse_x = mouse_y = -1; mouse_x = mouse_y = -1;
}
PIScreen::SystemConsole::~SystemConsole() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
void PIScreen::SystemConsole::begin() {
int w, h; int w, h;
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->ulcoord.X = 0; PRIVATE->ulcoord.X = 0;
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE); PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
PRIVATE->dattr = PRIVATE->sbi.wAttributes; PRIVATE->dattr = PRIVATE->sbi.wAttributes;
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left; w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top; h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top; PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode); GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
@@ -90,6 +74,18 @@ void PIScreen::SystemConsole::begin() {
# endif # endif
#endif #endif
resize(w, h); resize(w, h);
}
PIScreen::SystemConsole::~SystemConsole() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
void PIScreen::SystemConsole::begin() {
#ifdef WINDOWS #ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT); SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -97,7 +93,6 @@ void PIScreen::SystemConsole::begin() {
PRIVATE->bc.Y = 0; PRIVATE->bc.Y = 0;
#endif #endif
clear(); clear();
clearScreen();
hideCursor(); hideCursor();
} }
@@ -139,9 +134,9 @@ void PIScreen::SystemConsole::clear() {
void PIScreen::SystemConsole::resize(int w, int h) { void PIScreen::SystemConsole::resize(int w, int h) {
if (w == pwidth && h == pheight) return; if (w == pwidth && h == pheight) return;
width = piMaxi(w, 0); width = piMaxi(w, 0);
height = piMaxi(h, 0); height = piMaxi(h, 0);
pwidth = width; pwidth = width;
pheight = height; pheight = height;
cells.resize(height); cells.resize(height);
pcells.resize(height); pcells.resize(height);
@@ -162,7 +157,7 @@ void PIScreen::SystemConsole::resize(int w, int h) {
void PIScreen::SystemConsole::print() { void PIScreen::SystemConsole::print() {
if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) { if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) {
/// cells[mouse_y][mouse_x].format.flags ^= Inverse; ///cells[mouse_y][mouse_x].format.flags ^= Inverse;
} }
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->srect = PRIVATE->sbi.srWindow; PRIVATE->srect = PRIVATE->sbi.srWindow;
@@ -190,10 +185,10 @@ void PIScreen::SystemConsole::print() {
int k = j * dw + i; int k = j * dw + i;
Cell & c(cells[j + dy0][i + dx0]); Cell & c(cells[j + dy0][i + dx0]);
PRIVATE->chars[k].Char.UnicodeChar = 0; PRIVATE->chars[k].Char.UnicodeChar = 0;
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte(); PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
PRIVATE->chars[k].Attributes = attributes(c); PRIVATE->chars[k].Attributes = attributes(c);
} }
// piCout << "draw" << dw << dh; //piCout << "draw" << dw << dh;
PRIVATE->bs.X = dw; PRIVATE->bs.X = dw;
PRIVATE->bs.Y = dh; PRIVATE->bs.Y = dh;
PRIVATE->srect.Left += dx0; PRIVATE->srect.Left += dx0;
@@ -232,7 +227,7 @@ void PIScreen::SystemConsole::print() {
if (!s.isEmpty()) { if (!s.isEmpty()) {
moveTo(si, sj); moveTo(si, sj);
PICout::stdoutPIString(s); PICout::stdoutPIString(s);
// printf("%s", s.data()); //printf("%s", s.data());
s.clear(); s.clear();
} }
} }
@@ -244,37 +239,33 @@ void PIScreen::SystemConsole::print() {
#ifdef WINDOWS #ifdef WINDOWS
# define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
# define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) #define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr; WORD attr = PRIVATE->dattr;
if (c.format.flags & Bold) if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY;
attr |= FOREGROUND_INTENSITY; else attr &= ~FOREGROUND_INTENSITY;
else if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE;
attr &= ~FOREGROUND_INTENSITY; else attr &= ~COMMON_LVB_UNDERSCORE;
if (c.format.flags & Underline)
attr |= COMMON_LVB_UNDERSCORE;
else
attr &= ~COMMON_LVB_UNDERSCORE;
switch (c.format.color_char) { switch (c.format.color_char) {
case Black: attr = (attr & ~FOREGROUND_MASK); break; case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break; case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break; case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break;
case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break; case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break;
case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break; case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case Magenta: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_BLUE; break; case Magenta: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_BLUE; break;
case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break; case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case White: attr = attr | FOREGROUND_MASK; break; case White: attr = attr | FOREGROUND_MASK; break;
} }
switch (c.format.color_back) { switch (c.format.color_back) {
case Black: attr = (attr & ~BACKGROUND_MASK); break; case Black: attr = (attr & ~BACKGROUND_MASK); break;
case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break; case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break;
case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break; case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break;
case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break; case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break;
case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break; case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case Magenta: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_BLUE; break; case Magenta: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_BLUE; break;
case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break; case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case White: attr = attr | BACKGROUND_MASK; break; case White: attr = attr | BACKGROUND_MASK; break;
} }
if ((c.format.flags & Inverse) == Inverse) { if ((c.format.flags & Inverse) == Inverse) {
uchar f = attr & 0xFF; uchar f = attr & 0xFF;
@@ -284,8 +275,8 @@ ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
} }
return attr; return attr;
} }
# undef FOREGROUND_MASK #undef FOREGROUND_MASK
# undef BACKGROUND_MASK #undef BACKGROUND_MASK
void PIScreen::SystemConsole::getWinCurCoord() { void PIScreen::SystemConsole::getWinCurCoord() {
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
@@ -300,37 +291,36 @@ void PIScreen::SystemConsole::clearLine() {
void PIScreen::SystemConsole::newLine() { void PIScreen::SystemConsole::newLine() {
getWinCurCoord(); getWinCurCoord();
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
} }
#else // WINDOWS #else // WINDOWS
PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) { PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) {
PIString ts = PIStringAscii("\e[0"); PIString ts = PIStringAscii("\e[0");
switch (c.format.color_char) { switch (c.format.color_char) {
case Black: ts += PIStringAscii(";30"); break; case Black: ts += PIStringAscii(";30"); break;
case Red: ts += PIStringAscii(";31"); break; case Red: ts += PIStringAscii(";31"); break;
case Green: ts += PIStringAscii(";32"); break; case Green: ts += PIStringAscii(";32"); break;
case Blue: ts += PIStringAscii(";34"); break; case Blue: ts += PIStringAscii(";34"); break;
case Cyan: ts += PIStringAscii(";36"); break; case Cyan: ts += PIStringAscii(";36"); break;
case Magenta: ts += PIStringAscii(";35"); break; case Magenta: ts += PIStringAscii(";35"); break;
case Yellow: ts += PIStringAscii(";33"); break; case Yellow: ts += PIStringAscii(";33"); break;
case White: ts += PIStringAscii(";37"); break; case White: ts += PIStringAscii(";37"); break;
} }
switch (c.format.color_back) { switch (c.format.color_back) {
case Black: ts += PIStringAscii(";40"); break; case Black: ts += PIStringAscii(";40"); break;
case Red: ts += PIStringAscii(";41"); break; case Red: ts += PIStringAscii(";41"); break;
case Green: ts += PIStringAscii(";42"); break; case Green: ts += PIStringAscii(";42"); break;
case Blue: ts += PIStringAscii(";44"); break; case Blue: ts += PIStringAscii(";44"); break;
case Cyan: ts += PIStringAscii(";46"); break; case Cyan: ts += PIStringAscii(";46"); break;
case Magenta: ts += PIStringAscii(";45"); break; case Magenta: ts += PIStringAscii(";45"); break;
case Yellow: ts += PIStringAscii(";43"); break; case Yellow: ts += PIStringAscii(";43"); break;
case White: ts += PIStringAscii(";47"); break; case White: ts += PIStringAscii(";47"); break;
} }
if ((c.format.flags & Bold) == Bold) ts += PIStringAscii(";1"); if ((c.format.flags & Bold ) == Bold ) ts += PIStringAscii(";1");
if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4"); if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4");
if ((c.format.flags & Blink) == Blink) ts += PIStringAscii(";5"); if ((c.format.flags & Blink ) == Blink ) ts += PIStringAscii(";5");
if ((c.format.flags & Inverse) == Inverse) ts += PIStringAscii(";7"); if ((c.format.flags & Inverse ) == Inverse ) ts += PIStringAscii(";7");
return ts + 'm'; return ts + 'm';
} }
#endif // WINDOWS #endif // WINDOWS
@@ -367,16 +357,8 @@ void PIScreen::SystemConsole::clearScreen() {
void PIScreen::SystemConsole::clearScreenLower() { void PIScreen::SystemConsole::clearScreenLower() {
#ifdef WINDOWS #ifdef WINDOWS
getWinCurCoord(); getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
PRIVATE->dattr, FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut,
' ',
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
#else #else
printf("\e[0m\e[J"); printf("\e[0m\e[J");
#endif #endif
@@ -401,33 +383,34 @@ void PIScreen::SystemConsole::showCursor() {
} }
// PIScreen
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") { PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen"); setName("screen");
setPriority(piLow); setPriority(piLow);
needLockRun(true); needLockRun(true);
mouse_ = false; mouse_ = false;
ret_func = slot; ret_func = slot;
tile_focus = tile_dialog = nullptr; tile_focus = tile_dialog = 0;
root.screen = this; root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow); listener = new PIKbdListener(key_eventS, this, startNow);
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event); CONNECTU(listener, mouseEvent, this, mouse_event);
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event); CONNECTU(listener, wheelEvent, this, wheel_event);
if (startNow) start(); if (startNow) start();
} }
PIScreen::~PIScreen() { PIScreen::~PIScreen() {
if (isRunning()) stop(); if (isRunning())
PIThread::waitForFinish(100_ms); stop();
listener->waitForFinish(100_ms); PIThread::waitForFinish(10);
listener->waitForFinish(10);
delete listener; delete listener;
} }
void PIScreen::setMouseEnabled(bool on) { void PIScreen::setMouseEnabled(bool on) {
mouse_ = on; mouse_ = on;
console.mouse_x = console.mouse_y = -1; console.mouse_x = console.mouse_y = -1;
} }
@@ -439,12 +422,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
return; return;
*/ */
PIScreenTile * rtile = rootTile(); PIScreenTile * rtile = rootTile();
if (tile_dialog) rtile = tile_dialog; if (tile_dialog)
rtile = tile_dialog;
bool used = nextFocus(rtile, key); bool used = nextFocus(rtile, key);
if (used) return; if (used) return;
if (!used && tile_focus) { if (!used && tile_focus) {
if (tile_focus->visible) { if (tile_focus->visible) {
if (tile_focus->keyEvent(key)) return; if (tile_focus->keyEvent(key))
return;
} }
} }
if (ret_func != 0) ret_func(key, data_); if (ret_func != 0) ret_func(key, data_);
@@ -452,14 +437,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
} }
PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) { PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile *> ret; PIVector<PIScreenTile * > ret;
if (!mouse_ || !e) return ret; if (!mouse_ || !e) return ret;
console.mouse_x = e->x; console.mouse_x = e->x;
console.mouse_y = e->y; console.mouse_y = e->y;
PIVector<PIScreenTile *> tl = tilesUnderMouse(e->x, e->y); PIVector<PIScreenTile * > tl = tilesUnderMouse(e->x, e->y);
bool ff = false; bool ff = false;
piForeachR(PIScreenTile * t, tl) { piForeachR (PIScreenTile * t, tl) {
if (!ff) { if (!ff) {
if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) { if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) {
t->setFocus(); t->setFocus();
@@ -470,19 +455,20 @@ PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
ff = true; ff = true;
} }
} }
} }
return tl; return tl;
} }
PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) { PIVector<PIScreenTile * > PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile *> ret; PIVector<PIScreenTile * > ret;
if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret; if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret;
PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile(); PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile();
bool f = true; bool f = true;
while (ct) { while (ct) {
if (!f) ret << ct; if (!f) ret << ct;
f = false; f = false;
ct = ct->childUnderMouse(x, y); ct = ct->childUnderMouse(x, y);
} }
return ret; return ret;
@@ -490,25 +476,27 @@ PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) {
void PIScreen::mouse_event(PIKbdListener::MouseEvent me) { void PIScreen::mouse_event(PIKbdListener::MouseEvent me) {
PIVector<PIScreenTile *> tl = prepareMouse(&me); PIVector<PIScreenTile * > tl = prepareMouse(&me);
if (tl.isEmpty()) return; if (tl.isEmpty()) return;
piForeachR(PIScreenTile * t, tl) piForeachR (PIScreenTile * t, tl)
if (t->mouseEvent(me)) break; if (t->mouseEvent(me)) break;
} }
void PIScreen::wheel_event(PIKbdListener::WheelEvent we) { void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
PIVector<PIScreenTile *> tl = prepareMouse(&we); PIVector<PIScreenTile * > tl = prepareMouse(&we);
if (tl.isEmpty()) return; if (tl.isEmpty()) return;
piForeachR(PIScreenTile * t, tl) piForeachR (PIScreenTile * t, tl)
if (t->wheelEvent(we)) break; if (t->wheelEvent(we)) break;
} }
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) { bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile *> vtl = rt->children(true), ftl; PIVector<PIScreenTile*> vtl = rt->children(true), ftl;
for (PIScreenTile * t: vtl) { piForeach (PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus]) ftl << t; if (t->focus_flags[CanHasFocus])
ftl << t;
} }
int ind = -1; int ind = -1;
for (int i = 0; i < ftl.size_s(); ++i) for (int i = 0; i < ftl.size_s(); ++i)
@@ -516,15 +504,18 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
ind = i; ind = i;
break; break;
} }
if (ind < 0) tile_focus = 0; if (ind < 0)
tile_focus = 0;
if (ftl.isEmpty()) if (ftl.isEmpty())
tile_focus = 0; tile_focus = 0;
else { else {
if (tile_focus) if (tile_focus)
if (!tile_focus->visible) tile_focus = 0; if (!tile_focus->visible)
tile_focus = 0;
int next = tile_focus ? 0 : 1; int next = tile_focus ? 0 : 1;
if (tile_focus) { if (tile_focus) {
if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) next = 1; if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab)
next = 1;
if (tile_focus->focus_flags[NextByArrowsHorizontal]) { if (tile_focus->focus_flags[NextByArrowsHorizontal]) {
if (key.key == PIKbdListener::LeftArrow) next = -1; if (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1; if (key.key == PIKbdListener::RightArrow) next = 1;
@@ -534,16 +525,16 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
if (key.key == PIKbdListener::DownArrow) next = 1; if (key.key == PIKbdListener::DownArrow) next = 1;
} }
} }
// piCout << ftl.size() << ind << next; //piCout << ftl.size() << ind << next;
if (next != 0) { if (next != 0) {
PIVector<PIScreenTile *> tl = rt->children(); PIVector<PIScreenTile*> tl = rt->children();
for (PIScreenTile * t: tl) piForeach (PIScreenTile * t, tl)
t->has_focus = false; t->has_focus = false;
if (!ftl.isEmpty()) { if (!ftl.isEmpty()) {
ind += next; ind += next;
if (ind >= ftl.size_s()) ind = 0; if (ind >= ftl.size_s()) ind = 0;
if (ind < 0) ind = ftl.size_s() - 1; if (ind < 0) ind = ftl.size_s() - 1;
tile_focus = ftl[ind]; tile_focus = ftl[ind];
tile_focus->has_focus = true; tile_focus->has_focus = true;
} }
return true; return true;
@@ -559,19 +550,22 @@ void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
void PIScreen::tileRemovedInternal(PIScreenTile * t) { void PIScreen::tileRemovedInternal(PIScreenTile * t) {
if (tile_dialog == t) tile_dialog = 0; if (tile_dialog == t)
tile_dialog = 0;
} }
void PIScreen::tileSetFocusInternal(PIScreenTile * t) { void PIScreen::tileSetFocusInternal(PIScreenTile * t) {
PIScreenTile * rt = rootTile(); PIScreenTile * rt = rootTile();
if (tile_dialog) rt = tile_dialog; if (tile_dialog)
PIVector<PIScreenTile *> tl = rt->children(), ftl; rt = tile_dialog;
for (PIScreenTile * i: tl) PIVector<PIScreenTile*> tl = rt->children(), ftl;
piForeach (PIScreenTile * i, tl)
i->has_focus = false; i->has_focus = false;
tile_focus = t; tile_focus = t;
if (!tile_focus) return; if (!tile_focus) return;
if (tile_focus->focus_flags[CanHasFocus]) tile_focus->has_focus = true; if (tile_focus->focus_flags[CanHasFocus])
tile_focus->has_focus = true;
} }
@@ -593,14 +587,8 @@ void PIScreen::waitForFinish() {
} }
void PIScreen::start(bool wait) {
PIThread::start(25_Hz);
if (wait) waitForFinish();
}
void PIScreen::stop(bool clear) { void PIScreen::stop(bool clear) {
PIThread::stopAndWait(); PIThread::stop(true);
if (clear) console.clearScreen(); if (clear) console.clearScreen();
#ifndef WINDOWS #ifndef WINDOWS
fflush(0); fflush(0);
@@ -624,21 +612,16 @@ void PIScreen::run() {
if (tile_dialog) { if (tile_dialog) {
int sw(0), sh(0); int sw(0), sh(0);
tile_dialog->sizeHint(sw, sh); tile_dialog->sizeHint(sw, sh);
sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth); sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth);
sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight); sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight);
tile_dialog->x_ = (console.width - sw) / 2; tile_dialog->x_ = (console.width - sw) / 2;
tile_dialog->y_ = (console.height - sh) / 2; tile_dialog->y_ = (console.height - sh) / 2;
tile_dialog->width_ = sw; tile_dialog->width_ = sw;
tile_dialog->height_ = sh; tile_dialog->height_ = sh;
tile_dialog->layout(); tile_dialog->layout();
int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_; int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_;
drawer_.drawFrame(dx, drawer_.drawFrame(dx, dy, dx + dw + 1, dy + dh + 1, (Color)tile_dialog->back_format.color_char,
dy, (Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags);
dx + dw + 1,
dy + dh + 1,
(Color)tile_dialog->back_format.color_char,
(Color)tile_dialog->back_format.color_back,
(CharFlags)tile_dialog->back_format.flags);
tile_dialog->drawEventInternal(&drawer_); tile_dialog->drawEventInternal(&drawer_);
} }
console.print(); console.print();
@@ -652,8 +635,10 @@ void PIScreen::end() {
PIScreenTile * PIScreen::tileByName(const PIString & name) { PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile *> tl(tiles()); PIVector<PIScreenTile*> tl(tiles());
for (PIScreenTile * t: tl) piForeach (PIScreenTile * t, tl)
if (t->name() == name) return t; if (t->name() == name)
return t;
return 0; return 0;
} }

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API Tile for PIScreen with PIConsole API
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreenconsole.h" #include "piscreenconsole.h"
@@ -22,14 +22,21 @@
using namespace PIScreenTypes; using namespace PIScreenTypes;
TileVars::TileVars(const PIString & n): PIScreenTile(n) { TileVars::TileVars(const PIString &n) : PIScreenTile(n) {
alignment = Left; alignment = Left;
} }
void TileVars::sizeHint(int & w, int & h) const {} void TileVars::sizeHint(int &w, int &h) const {
void TileVars::drawEvent(PIScreenDrawer * d) {} }
void TileVars::drawEvent(PIScreenDrawer *d) {
}
PIScreenConsoleTile::PIScreenConsoleTile() {} PIScreenConsoleTile::PIScreenConsoleTile() {
}

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Console output/input Console output/input
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -25,68 +25,68 @@
using namespace PIScreenTypes; using namespace PIScreenTypes;
PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell>> & c): cells(c) { PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell> > & c): cells(c) {
arts_[LineVertical] = arts_[LineVertical] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('|'); PIChar('|');
#endif #endif
arts_[LineHorizontal] = arts_[LineHorizontal] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('-'); PIChar('-');
#endif #endif
arts_[Cross] = arts_[Cross] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerTopLeft] = arts_[CornerTopLeft] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerTopRight] = arts_[CornerTopRight] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerBottomLeft] = arts_[CornerBottomLeft] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[CornerBottomRight] = arts_[CornerBottomRight] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('+'); PIChar('+');
#endif #endif
arts_[Unchecked] = arts_[Unchecked] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('O'); PIChar('O');
#endif #endif
arts_[Checked] = arts_[Checked] =
#ifdef USE_UNICODE #ifdef USE_UNICODE
PIChar::fromUTF8(""); PIChar::fromUTF8("");
#else #else
PIChar('0'); PIChar('0');
#endif #endif
} }
@@ -98,43 +98,45 @@ void PIScreenDrawer::clear() {
void PIScreenDrawer::drawPixel(int x, int y, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::drawPixel(int x, int y, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x < 0 || x >= width || y < 0 || y >= height) return; if (x < 0 || x >= width || y < 0 || y >= height) return;
cells[y][x].symbol = c; cells[y][x].symbol = c;
cells[y][x].format.color_char = col_char; cells[y][x].format.color_char = col_char;
cells[y][x].format.color_back = col_back; cells[y][x].format.color_back = col_back;
cells[y][x].format.flags = flags_char; cells[y][x].format.flags = flags_char;
} }
void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc; Cell cc;
cc.symbol = c; cc.symbol = c;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int x = 0, y = 0; int x = 0, y = 0;
if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) { if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) {
float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0; float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
for (int i = x0; i != x1; i += dx) { for (int i = x0; i != x1; i += dx) {
x = i; x = i; y = piRound(cy);
y = piRound(cy); if (x >= 0 && x < width && y >= 0 && y < height)
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc; cells[y][x] = cc;
cy += dy; cy += dy;
} }
y = piRound(cy); y = piRound(cy);
if (x1 >= 0 && x1 < width && y >= 0 && y < height) cells[y][x1] = cc; if (x1 >= 0 && x1 < width && y >= 0 && y < height)
cells[y][x1] = cc;
} else { } else {
float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0; float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
for (int i = y0; i != y1; i += dy) { for (int i = y0; i != y1; i += dy) {
x = piRound(cx); x = piRound(cx); y = i;
y = i; if (x >= 0 && x < width && y >= 0 && y < height)
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc; cells[y][x] = cc;
cx += dx; cx += dx;
} }
x = piRound(cx); x = piRound(cx);
if (x >= 0 && x < width && y1 >= 0 && y1 < height) cells[y1][x] = cc; if (x >= 0 && x < width && y1 >= 0 && y1 < height)
cells[y1][x] = cc;
} }
} }
@@ -142,29 +144,32 @@ void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c,
void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc; Cell cc;
cc.symbol = c; cc.symbol = c;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1}; int xs[2] = {x0, x1};
int ys[2] = {y0, y1}; int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) { for (int k = 0; k < 2; ++k) {
int j = ys[k]; int j = ys[k];
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width) cv[i] = cc; if (i >= 0 && i < width)
cv[i] = cc;
} }
j = xs[k]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
for (int i = y0; i != y1; i += dy) for (int i = y0; i != y1; i += dy)
if (i >= 0 && i < height) cells[i][j] = cc; if (i >= 0 && i < height)
cells[i][j] = cc;
} }
} }
int i = x1, j = y1; int i = x1, j = y1;
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height)
cells[j][i] = cc;
} }
@@ -173,37 +178,35 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
Cell cc; Cell cc;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1}; int xs[2] = {x0, x1};
int ys[2] = {y0, y1}; int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) { for (int k = 0; k < 2; ++k) {
int j = ys[k]; int j = ys[k];
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
cc.symbol = artChar(LineHorizontal); cc.symbol = artChar(LineHorizontal);
for (int i = x0 + 1; i != x1; i += dx) for (int i = x0 + 1; i != x1; i += dx)
if (i >= 0 && i < width) cv[i] = cc; if (i >= 0 && i < width)
cv[i] = cc;
} }
j = xs[k]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
cc.symbol = artChar(LineVertical); cc.symbol = artChar(LineVertical);
for (int i = y0 + 1; i != y1; i += dy) for (int i = y0 + 1; i != y1; i += dy)
if (i >= 0 && i < height) cells[i][j] = cc; if (i >= 0 && i < height)
cells[i][j] = cc;
} }
} }
int i = x0, j = y0; int i = x0, j = y0; cc.symbol = artChar(CornerTopLeft);
cc.symbol = artChar(CornerTopLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y0; i = x1, j = y0; cc.symbol = artChar(CornerTopRight);
cc.symbol = artChar(CornerTopRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x0, j = y1; i = x0, j = y1; cc.symbol = artChar(CornerBottomLeft);
cc.symbol = artChar(CornerBottomLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y1; i = x1, j = y1; cc.symbol = artChar(CornerBottomRight);
cc.symbol = artChar(CornerBottomRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
} }
@@ -211,22 +214,23 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) { void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char); if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc; Cell cc;
cc.symbol = c; cc.symbol = c;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
for (int j = y0; j != y1; j += dy) for (int j = y0; j != y1; j += dy)
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width) cv[i] = cc; if (i >= 0 && i < width)
cv[i] = cc;
} }
} }
void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<Cell>> & content) { void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<Cell> > & content) {
if (x0 > x1) piSwap(x0, x1); if (x0 > x1) piSwap(x0, x1);
if (y0 > y1) piSwap(y0, y1); if (y0 > y1) piSwap(y0, y1);
int w = x1 - x0; int w = x1 - x0;
@@ -237,13 +241,14 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<
PIVector<Cell> & cv(cells[y0 + j]); PIVector<Cell> & cv(cells[y0 + j]);
PIVector<Cell> & contv(content[j]); PIVector<Cell> & contv(content[j]);
for (int i = 0; i < piMini(w, contv.size_s()); ++i) for (int i = 0; i < piMini(w, contv.size_s()); ++i)
if ((i + x0) >= 0 && (i + x0) < width) cv[x0 + i] = contv[i]; if ((i + x0) >= 0 && (i + x0) < width)
cv[x0 + i] = contv[i];
} }
} }
} }
void PIScreenDrawer::clear(PIVector<PIVector<Cell>> & cells) { void PIScreenDrawer::clear(PIVector<PIVector<Cell> > & cells) {
for (int i = 0; i < cells.size_s(); ++i) for (int i = 0; i < cells.size_s(); ++i)
cells[i].fill(Cell()); cells[i].fill(Cell());
} }
@@ -255,12 +260,12 @@ void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char,
Cell cc; Cell cc;
cc.format.color_char = col_char; cc.format.color_char = col_char;
cc.format.color_back = col_back; cc.format.color_back = col_back;
cc.format.flags = flags_char; cc.format.flags = flags_char;
for (int i = 0; i < s.size_s(); ++i) { for (int i = 0; i < s.size_s(); ++i) {
int j = i + x; int j = i + x;
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
cc.symbol = s[i]; cc.symbol = s[i];
cv[j] = cc; cv[j] = cc;
} }
} }
} }

View File

@@ -1,24 +1,23 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Basic PIScreen tile Basic PIScreen tile
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreentile.h" #include "piscreentile.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -26,23 +25,24 @@ using namespace PIScreenTypes;
PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) { PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) {
direction = d; direction = d;
size_policy = p; size_policy = p;
focus_flags = 0; focus_flags = 0;
screen = 0; screen = 0;
minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0; minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0;
maximumWidth = maximumHeight = 65535; maximumWidth = maximumHeight = 65535;
marginLeft = marginRight = marginTop = marginBottom = spacing = 0; marginLeft = marginRight = marginTop = marginBottom = spacing = 0;
parent = 0; parent = 0;
back_symbol = ' '; back_symbol = ' ';
visible = true; visible = true;
has_focus = false; has_focus = false;
} }
PIScreenTile::~PIScreenTile() { PIScreenTile::~PIScreenTile() {
// piCout << this << "~"; //piCout << this << "~";
if (screen) screen->tileRemovedInternal(this); if (screen)
screen->tileRemovedInternal(this);
setScreen(0); setScreen(0);
deleteChildren(); deleteChildren();
if (!parent) return; if (!parent) return;
@@ -76,18 +76,20 @@ void PIScreenTile::removeTile(PIScreenTile * t) {
} }
PIVector<PIScreenTile *> PIScreenTile::children(bool only_visible) { PIVector<PIScreenTile * > PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile *> ret; PIVector<PIScreenTile * > ret;
for (auto * t: tiles) piForeach (PIScreenTile * t, tiles)
if (t->visible || !only_visible) ret << t << t->children(only_visible); if (t->visible || !only_visible)
ret << t << t->children(only_visible);
return ret; return ret;
} }
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) { PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
for (auto * t: tiles) { piForeach (PIScreenTile * t, tiles) {
if (!t->visible) continue; if (!t->visible) continue;
if (x >= t->x_ && (x - t->x_) < t->width_ && y >= t->y_ && (y - t->y_) < t->height_) { if (x >= t->x_ && (x - t->x_) < t->width_ &&
y >= t->y_ && (y - t->y_) < t->height_) {
return t; return t;
} }
} }
@@ -103,13 +105,13 @@ void PIScreenTile::raiseEvent(TileEvent e) {
void PIScreenTile::setScreen(PIScreenBase * s) { void PIScreenTile::setScreen(PIScreenBase * s) {
screen = s; screen = s;
for (auto * t: tiles) piForeach (PIScreenTile * t, tiles)
t->setScreen(s); t->setScreen(s);
} }
void PIScreenTile::deleteChildren() { void PIScreenTile::deleteChildren() {
for (auto * t: tiles) { piForeach (PIScreenTile * t, tiles) {
t->parent = 0; t->parent = 0;
delete t; delete t;
} }
@@ -127,16 +129,9 @@ void PIScreenTile::drawEventInternal(PIScreenDrawer * d) {
if (!visible) { if (!visible) {
return; return;
} }
d->fillRect(x_, d->fillRect(x_, y_, x_ + width_, y_ + height_, back_symbol, (Color)back_format.color_char, (Color)back_format.color_back, back_format.flags);
y_,
x_ + width_,
y_ + height_,
back_symbol,
(Color)back_format.color_char,
(Color)back_format.color_back,
back_format.flags);
drawEvent(d); drawEvent(d);
for (auto * t: tiles) piForeach (PIScreenTile * t, tiles)
t->drawEventInternal(d); t->drawEventInternal(d);
} }
@@ -146,22 +141,18 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
h = 0; h = 0;
if (tiles.isEmpty()) return; if (tiles.isEmpty()) return;
int sl = spacing * (tiles.size_s() - 1); int sl = spacing * (tiles.size_s() - 1);
if (direction == Horizontal) if (direction == Horizontal) w += sl;
w += sl; else h += sl;
else piForeachC (PIScreenTile * t, tiles) {
h += sl;
for (const auto * t: tiles) {
if (!t->visible) continue; if (!t->visible) continue;
int cw(0), ch(0); int cw(0), ch(0);
t->sizeHint(cw, ch); t->sizeHint(cw, ch);
cw = piClampi(cw, t->minimumWidth, t->maximumWidth); cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
ch = piClampi(ch, t->minimumHeight, t->maximumHeight); ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
if (direction == Horizontal) { if (direction == Horizontal) {
w += cw; w += cw; h = piMaxi(h, ch);
h = piMaxi(h, ch);
} else { } else {
h += ch; h += ch; w = piMaxi(w, cw);
w = piMaxi(w, cw);
} }
} }
w += marginLeft + marginRight; w += marginLeft + marginRight;
@@ -172,7 +163,7 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
void PIScreenTile::layout() { void PIScreenTile::layout() {
if (tiles.isEmpty() || !visible) return; if (tiles.isEmpty() || !visible) return;
int as(0), ts(0), ts2(0), ecnt(0), pcnt(0); int as(0), ts(0), ts2(0), ecnt(0), pcnt(0);
ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom); ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
ts -= spacing * (tiles.size_s() - 1); ts -= spacing * (tiles.size_s() - 1);
PIVector<int> hints(tiles.size_s()); PIVector<int> hints(tiles.size_s());
@@ -189,7 +180,7 @@ void PIScreenTile::layout() {
cs = (direction == Horizontal) ? cw : ch; cs = (direction == Horizontal) ? cw : ch;
as += cs; as += cs;
} }
hints[i] = cs; hints[i] = cs;
asizes[i] = 0.f; asizes[i] = 0.f;
} }
if (as <= ts) { if (as <= ts) {
@@ -197,10 +188,10 @@ void PIScreenTile::layout() {
SizePolicy pol = Fixed; SizePolicy pol = Fixed;
if (ecnt > 0) { if (ecnt > 0) {
acnt = ecnt; acnt = ecnt;
pol = Expanding; pol = Expanding;
} else if (pcnt > 0) { } else if (pcnt > 0) {
acnt = pcnt; acnt = pcnt;
pol = Preferred; pol = Preferred;
} }
if (acnt > 0) { if (acnt > 0) {
float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.); float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.);
@@ -219,7 +210,8 @@ void PIScreenTile::layout() {
for (int j = 0; j < tiles.size_s(); ++j) { for (int j = 0; j < tiles.size_s(); ++j) {
if (i == j) continue; if (i == j) continue;
if (max_tl[j]) continue; if (max_tl[j]) continue;
if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout()) asizes[j] += pas; if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout())
asizes[j] += pas;
} }
} }
} }
@@ -241,15 +233,16 @@ void PIScreenTile::layout() {
t->x_ = cx; t->x_ = cx;
t->y_ = cy; t->y_ = cy;
if (direction == Horizontal) { if (direction == Horizontal) {
t->width_ = hints[i]; t->width_ = hints[i];
t->height_ = ts2; t->height_ = ts2;
cx += hints[i] + spacing; cx += hints[i] + spacing;
} else { } else {
t->width_ = ts2; t->width_ = ts2;
t->height_ = hints[i]; t->height_ = hints[i];
cy += hints[i] + spacing; cy += hints[i] + spacing;
} }
if (t->pw != t->width_ || t->ph != t->height_) t->resizeEvent(t->width_, t->height_); if (t->pw != t->width_ || t->ph != t->height_)
t->resizeEvent(t->width_, t->height_);
t->pw = t->width_; t->pw = t->width_;
t->ph = t->height_; t->ph = t->height_;
t->layout(); t->layout();

View File

@@ -1,24 +1,23 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Various tiles for PIScreen Various tiles for PIScreen
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreentiles.h" #include "piscreentiles.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -38,7 +37,7 @@ TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() {
void TileSimple::sizeHint(int & w, int & h) const { void TileSimple::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
for (const auto & r: content) piForeachC (Row & r, content)
w = piMaxi(w, r.first.size_s()); w = piMaxi(w, r.first.size_s());
h = content.size_s(); h = content.size_s();
} }
@@ -58,13 +57,13 @@ void TileSimple::drawEvent(PIScreenDrawer * d) {
} }
// TileScrollBar
TileScrollBar::TileScrollBar(const PIString & n) { TileScrollBar::TileScrollBar(const PIString & n) {
direction = Vertical; direction = Vertical;
thickness = 1; thickness = 1;
minimum_ = value_ = 0; minimum_ = value_ = 0;
maximum_ = 100; maximum_ = 100;
} }
@@ -123,15 +122,15 @@ bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileList
TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) { TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
alignment = Left; alignment = Left;
focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel; focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel;
lhei = offset = cur = 0; lhei = offset = cur = 0;
mouse_sel = false; mouse_sel = false;
selection_mode = sm; selection_mode = sm;
scroll = new TileScrollBar(); scroll = new TileScrollBar();
scroll->size_policy = Ignore; scroll->size_policy = Ignore;
addTile(scroll); addTile(scroll);
} }
@@ -139,26 +138,26 @@ TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
void TileList::sizeHint(int & w, int & h) const { void TileList::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
for (const auto & r: content) piForeachC (Row & r, content)
w = piMaxi(w, r.first.size_s()); w = piMaxi(w, r.first.size_s());
h = 3; h = 3;
} }
void TileList::resizeEvent(int w, int h) { void TileList::resizeEvent(int w, int h) {
scroll->x_ = x_ + width_ - 1; scroll->x_ = x_ + width_ - 1;
scroll->y_ = y_; scroll->y_ = y_;
scroll->width_ = 1; scroll->width_ = 1;
scroll->height_ = height_; scroll->height_ = height_;
} }
void TileList::drawEvent(PIScreenDrawer * d) { void TileList::drawEvent(PIScreenDrawer * d) {
lhei = height_ - 2; lhei = height_ - 2;
int is = piClampi(offset, 0, piMaxi(0, content.size_s() - 1)), ie = piClampi(offset + lhei, 0, content.size_s()); int is = piClampi(offset, 0, piMaxi(0, content.size_s() - 1)), ie = piClampi(offset + lhei, 0, content.size_s());
if (is > 0) d->drawText(x_, y_, PIString(" /\\ ").repeat(width_ / 4), Green, Default, Bold); if (is > 0) d->drawText(x_, y_, PIString(" /\\ ").repeat(width_ / 4), Green, Default, Bold);
if (ie < content.size_s()) d->drawText(x_, y_ + height_ - 1, PIString(" \\/ ").repeat(width_ / 4), Green, Default, Bold); if (ie < content.size_s()) d->drawText(x_, y_ + height_ - 1, PIString(" \\/ ").repeat(width_ / 4), Green, Default, Bold);
// piCout << is << ie << offset << lhei << content.size_s(); //piCout << is << ie << offset << lhei << content.size_s();
for (int i = is; i < ie; ++i) { for (int i = is; i < ie; ++i) {
Row & r(content[i]); Row & r(content[i]);
bool sel = i == cur && has_focus; bool sel = i == cur && has_focus;
@@ -173,7 +172,7 @@ void TileList::drawEvent(PIScreenDrawer * d) {
case Right: rx = x_ + width_ - 1 - r.first.size_s(); break; case Right: rx = x_ + width_ - 1 - r.first.size_s(); break;
}; };
CharFlags cf = r.second.flags; CharFlags cf = r.second.flags;
Color cc = (Color)r.second.color_char; Color cc = (Color)r.second.color_char;
if (selected[i]) { if (selected[i]) {
cf |= Bold; cf |= Bold;
cc = Yellow; cc = Yellow;
@@ -189,7 +188,9 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
lhei = height_ - 2; lhei = height_ - 2;
int oo(0), osp = piMini(3, lhei / 4); int oo(0), osp = piMini(3, lhei / 4);
switch (key.key) { switch (key.key) {
case PIKbdListener::PageUp: cur -= lhei / 2; oo -= lhei / 2; case PIKbdListener::PageUp:
cur -= lhei / 2;
oo -= lhei / 2;
case PIKbdListener::UpArrow: case PIKbdListener::UpArrow:
cur--; cur--;
oo--; oo--;
@@ -206,8 +207,7 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
switch (selection_mode) { switch (selection_mode) {
case NoSelection: return false; case NoSelection: return false;
case SingleSelection: case SingleSelection:
if (selected.isEmpty()) if (selected.isEmpty()) selected << cur;
selected << cur;
else { else {
bool add = !selected[cur]; bool add = !selected[cur];
selected.clear(); selected.clear();
@@ -216,10 +216,8 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
return true; return true;
case MultiSelection: case MultiSelection:
if (selected[cur]) if (selected[cur]) selected.remove(cur);
selected.remove(cur); else selected << cur;
else
selected << cur;
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
} }
@@ -240,14 +238,17 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei; if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
return true; return true;
case PIKbdListener::Home: cur = offset = 0; return true; case PIKbdListener::Home:
cur = offset = 0;
return true;
case PIKbdListener::End: case PIKbdListener::End:
cur = content.size_s() - 1; cur = content.size_s() - 1;
offset = content.size_s() - lhei; offset = content.size_s() - lhei;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
return true; return true;
case PIKbdListener::Return: case PIKbdListener::Return:
if (cur >= 0 && cur < content.size_s()) raiseEvent(TileEvent(RowPressed, cur)); if (cur >= 0 && cur < content.size_s())
raiseEvent(TileEvent(RowPressed, cur));
return true; return true;
case '*': case '*':
if (selection_mode == TileList::MultiSelection) { if (selection_mode == TileList::MultiSelection) {
@@ -277,8 +278,12 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
if (mp < 0 || mp >= content.size_s()) return true; if (mp < 0 || mp >= content.size_s()) return true;
cur = mp; cur = mp;
switch (me.action) { switch (me.action) {
case PIKbdListener::MouseButtonPress: mouse_sel = !selected.contains(cur); break; case PIKbdListener::MouseButtonPress:
case PIKbdListener::MouseButtonDblClick: keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); return true; mouse_sel = !selected.contains(cur);
break;
case PIKbdListener::MouseButtonDblClick:
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
return true;
default: break; default: break;
} }
if (me.buttons[PIKbdListener::MouseRight]) { if (me.buttons[PIKbdListener::MouseRight]) {
@@ -289,10 +294,8 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
case MultiSelection: case MultiSelection:
if (mouse_sel) if (mouse_sel) selected << cur;
selected << cur; else selected.remove(cur);
else
selected.remove(cur);
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
default: break; default: break;
@@ -308,7 +311,7 @@ bool TileList::wheelEvent(PIKbdListener::WheelEvent we) {
} }
// TileButton
TileButton::TileButton(const PIString & n): PIScreenTile(n) { TileButton::TileButton(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
@@ -324,7 +327,7 @@ void TileButton::sizeHint(int & w, int & h) const {
void TileButton::drawEvent(PIScreenDrawer * d) { void TileButton::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan; Color cb = has_focus ? Blue : Cyan;
Color ct = has_focus ? White : Black; Color ct = has_focus ? White : Black;
int ff = has_focus ? Bold : 0; int ff = has_focus ? Bold : 0;
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
d->drawText(x_, y_, "[", ct, Transparent, ff); d->drawText(x_, y_, "[", ct, Transparent, ff);
d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff); d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff);
@@ -348,25 +351,25 @@ bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileButtons
TileButtons::TileButtons(const PIString & n): PIScreenTile(n) { TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
direction = Horizontal; direction = Horizontal;
alignment = PIScreenTypes::Center; alignment = PIScreenTypes::Center;
cur = 0; cur = 0;
} }
void TileButtons::sizeHint(int & w, int & h) const { void TileButtons::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
if (direction == Horizontal) { if (direction == Horizontal) {
for (const auto & b: content) piForeachC (Button & b, content)
w += b.first.size_s() + 4; w += b.first.size_s() + 4;
w += piMaxi(0, content.size_s() - 1) * 2; w += piMaxi(0, content.size_s() - 1) * 2;
h += 1; h += 1;
} else { } else {
for (const auto & b: content) piForeachC (Button & b, content)
w = piMaxi(w, b.first.size_s() + 4); w = piMaxi(w, b.first.size_s() + 4);
h += content.size_s(); h += content.size_s();
h += piMaxi(0, content.size_s() - 1); h += piMaxi(0, content.size_s() - 1);
@@ -384,11 +387,12 @@ void TileButtons::drawEvent(PIScreenDrawer * d) {
case PIScreenTypes::Right: dx = width_ - shw; break; case PIScreenTypes::Right: dx = width_ - shw; break;
default: break; default: break;
} }
if (direction == PIScreenTypes::Horizontal) cx += dx; if (direction == PIScreenTypes::Horizontal)
cx += dx;
for (int i = 0; i < content.size_s(); ++i) { for (int i = 0; i < content.size_s(); ++i) {
Color cb = Cyan; Color cb = Cyan;
Color ct = Black; Color ct = Black;
int ff = 0; int ff = 0;
if (i == cur && has_focus) { if (i == cur && has_focus) {
cb = Blue; cb = Blue;
ct = White; ct = White;
@@ -426,7 +430,9 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
if (cur >= content.size_s()) cur = content.size_s() - 1; if (cur >= content.size_s()) cur = content.size_s() - 1;
return true; return true;
case PIKbdListener::Space: case PIKbdListener::Space:
case PIKbdListener::Return: raiseEvent(TileEvent(ButtonSelected, cur)); return true; case PIKbdListener::Return:
raiseEvent(TileEvent(ButtonSelected, cur));
return true;
}; };
return PIScreenTile::keyEvent(key); return PIScreenTile::keyEvent(key);
} }
@@ -435,7 +441,8 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) { bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) { if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) {
for (int i = 0; i < btn_rects.size_s(); ++i) for (int i = 0; i < btn_rects.size_s(); ++i)
if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 && me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) { if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 &&
me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) {
cur = i; cur = i;
break; break;
} }
@@ -447,11 +454,11 @@ bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileCheck
TileCheck::TileCheck(const PIString & n): PIScreenTile(n) { TileCheck::TileCheck(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
toggled = false; toggled = false;
} }
@@ -464,7 +471,7 @@ void TileCheck::sizeHint(int & w, int & h) const {
void TileCheck::drawEvent(PIScreenDrawer * d) { void TileCheck::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan; Color cb = has_focus ? Blue : Cyan;
Color ct = has_focus ? White : Black; Color ct = has_focus ? White : Black;
int ff = has_focus ? Bold : 0; int ff = has_focus ? Bold : 0;
PIString cs("[ ]"); PIString cs("[ ]");
if (toggled) cs[1] = '*'; if (toggled) cs[1] = '*';
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb); d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
@@ -492,12 +499,12 @@ bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileProgress
TileProgress::TileProgress(const PIString & n): PIScreenTile(n) { TileProgress::TileProgress(const PIString & n): PIScreenTile(n) {
maximum = 100.; maximum = 100.;
value = 0.; value = 0.;
suffix = " %"; suffix = " %";
} }
@@ -508,7 +515,7 @@ void TileProgress::sizeHint(int & w, int & h) const {
void TileProgress::drawEvent(PIScreenDrawer * d) { void TileProgress::drawEvent(PIScreenDrawer * d) {
int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100); int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100);
PIString s = prefix + PIString::fromNumber(piRoundd(value)) + suffix; PIString s = prefix + PIString::fromNumber(piRoundd(value)) + suffix;
int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2; int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2;
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan); d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan);
@@ -525,26 +532,28 @@ void TileProgress::drawEvent(PIScreenDrawer * d) {
} }
// TilePICout
TilePICout::TilePICout(const PIString & n): TileList(n) { TilePICout::TilePICout(const PIString & n): TileList(n) {
max_lines = 1024; max_lines = 1024;
selection_mode = TileList::SingleSelection; selection_mode = TileList::SingleSelection;
PICout::setOutputDevices(PICout::Buffer); PICout::setOutputDevices(PICout::Buffer);
PICout::setBufferActive(true);
} }
void TilePICout::drawEvent(PIScreenDrawer * d) { void TilePICout::drawEvent(PIScreenDrawer * d) {
PIString out = PICout::getBufferAndClear(); PIString out = PICout::buffer(true);
if (!out.isEmpty()) { if (!out.isEmpty()) {
PIStringList l = out.split("\n"); PIStringList l = out.split("\n");
bool scroll = (cur == content.size_s() - 1) || !has_focus; bool scroll = (cur == content.size_s() - 1) || !has_focus;
for (const auto & s: l) piForeachC (PIString & s, l)
content << TileList::Row(s.trimmed(), format); content << TileList::Row(s.trimmed(), format);
if (content.size_s() > max_lines) content.remove(0, content.size_s() - max_lines); if (content.size_s() > max_lines)
content.remove(0, content.size_s() - max_lines);
if (scroll) { if (scroll) {
offset = piMaxi(0, content.size_s() - lhei); offset = piMaxi(0, content.size_s() - lhei);
cur = content.size_s() - 1; cur = content.size_s() - 1;
} }
} }
TileList::drawEvent(d); TileList::drawEvent(d);
@@ -561,16 +570,16 @@ bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) {
} }
// TileInput
TileInput::TileInput(const PIString & n): PIScreenTile(n) { TileInput::TileInput(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
back_format.color_back = White; back_format.color_back = White;
format.color_char = Black; format.color_char = Black;
format.color_back = White; format.color_back = White;
max_length = 1024; max_length = 1024;
cur = offset = 0; cur = offset = 0;
inv = false; inv = false;
} }
@@ -583,8 +592,10 @@ void TileInput::sizeHint(int & w, int & h) const {
void TileInput::drawEvent(PIScreenDrawer * d) { void TileInput::drawEvent(PIScreenDrawer * d) {
PIString ps = text.mid(offset, width_ - 2); PIString ps = text.mid(offset, width_ - 2);
d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags); d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags);
if (offset > 0) d->drawText(x_, y_, "<", Green, Black, Bold); if (offset > 0)
if (text.size_s() - offset >= width_ - 2) d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold); d->drawText(x_, y_, "<", Green, Black, Bold);
if (text.size_s() - offset >= width_ - 2)
d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold);
if (!has_focus) return; if (!has_focus) return;
Color cb = (Color)format.color_char, cc = (Color)format.color_back; Color cb = (Color)format.color_char, cc = (Color)format.color_back;
if (tm_blink.elapsed_m() >= 650) { if (tm_blink.elapsed_m() >= 650) {
@@ -631,13 +642,14 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::End: case PIKbdListener::End:
cur = text.size_s(); cur = text.size_s();
offset = text.size_s() - lwid; offset = text.size_s() - lwid;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::Backspace: case PIKbdListener::Backspace:
if (cur > text.size_s() || text.isEmpty()) return true; if (cur > text.size_s() || text.isEmpty())
return true;
text.remove(cur - 1, 1); text.remove(cur - 1, 1);
cur--; cur--;
if (cur > text.size_s()) cur = text.size_s(); if (cur > text.size_s()) cur = text.size_s();
@@ -647,7 +659,8 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::Delete: case PIKbdListener::Delete:
if (cur >= text.size_s() || text.isEmpty()) return true; if (cur >= text.size_s() || text.isEmpty())
return true;
text.remove(cur, 1); text.remove(cur, 1);
if (cur < 0) cur = 0; if (cur < 0) cur = 0;
if (cur > text.size_s()) cur = text.size_s(); if (cur > text.size_s()) cur = text.size_s();
@@ -673,7 +686,8 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
case PIKbdListener::F9: case PIKbdListener::F9:
case PIKbdListener::F10: case PIKbdListener::F10:
case PIKbdListener::F11: case PIKbdListener::F11:
case PIKbdListener::F12: break; case PIKbdListener::F12:
break;
default: default:
text.insert(cur, PIChar((ushort)key.key)); text.insert(cur, PIChar((ushort)key.key));
cur++; cur++;

View File

@@ -1,60 +1,58 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Virtual terminal Virtual terminal
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piterminal.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piliterals_time.h" #include "piterminal.h"
#include "pisharedmemory.h" #include "pisharedmemory.h"
#ifndef MICRO_PIP #ifndef MICRO_PIP
# ifdef WINDOWS #ifdef WINDOWS
# include <windows.h> # include <windows.h>
# include <wingdi.h> # include <wingdi.h>
# include <winuser.h> # include <wincon.h>
# include <winuser.h>
#else
# include "piprocess.h"
# include <csignal>
# include <fcntl.h>
# include <sys/ioctl.h>
# if defined(QNX) || defined(BLACKBERRY)
# include <unix.h>
# else # else
# include "piprocess.h" # ifdef MAC_OS
# include <util.h>
# include <csignal> # else
# include <fcntl.h> # include <pty.h>
# include <sys/ioctl.h> # endif
# if defined(QNX) || defined(BLACKBERRY)
# include <unix.h>
# else
# ifdef MAC_OS
# include <util.h>
# else
# include <pty.h>
# endif
# endif
# ifdef ANDROID
# if __ANDROID_API__ >= 23
# define HAS_FORKPTY
# endif
# else
# define HAS_FORKPTY
# endif
# endif # endif
# ifdef ANDROID
# if __ANDROID_API__ >= 23
# define HAS_FORKPTY
# endif
# else
# define HAS_FORKPTY
# endif
#endif
// extern PIMutex PICout::__mutex__; //extern PIMutex PICout::__mutex__;
# ifdef WINDOWS #ifdef WINDOWS
# define PIPE_BUFFER_SIZE 1024 # define PIPE_BUFFER_SIZE 1024
enum PITerminalAuxMessageType { enum PITerminalAuxMessageType {
mtKey = 1, mtKey = 1,
mtResize, mtResize,
@@ -67,22 +65,22 @@ struct PITerminalAuxData {
int size_y; int size_y;
int cells_size; int cells_size;
}; };
# else #else
# define BUFFER_SIZE 4096 # define BUFFER_SIZE 4096
enum DECType { enum DECType {
CKM = 1 CKM = 1
}; };
# endif #endif
PRIVATE_DEFINITION_START(PITerminal) PRIVATE_DEFINITION_START(PITerminal)
# ifdef WINDOWS #ifdef WINDOWS
PISharedMemory * shm; PISharedMemory * shm;
HANDLE hConBuf; HANDLE hConBuf;
STARTUPINFOA si; STARTUPINFOA si;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
HANDLE pipe; HANDLE pipe;
# else #else
PIString shell; PIString shell;
PIByteArray read_buf, tmp_buf; PIByteArray read_buf, tmp_buf;
PIScreenTypes::CellFormat cur_format, line_format; PIScreenTypes::CellFormat cur_format, line_format;
@@ -94,21 +92,21 @@ PRIVATE_DEFINITION_START(PITerminal)
PIString esc_seq; PIString esc_seq;
bool is_esc_seq, last_read; bool is_esc_seq, last_read;
PIMap<int, bool> DEC; PIMap<int, bool> DEC;
PIVector<PIVector<PIScreenTypes::Cell>> cells_save; PIVector<PIVector<PIScreenTypes::Cell> > cells_save;
# endif #endif
PRIVATE_DEFINITION_END(PITerminal) PRIVATE_DEFINITION_END(PITerminal)
# ifdef WINDOWS #ifdef WINDOWS
int writePipe(HANDLE pipe, const PIByteArray & ba) { int writePipe(HANDLE pipe, const PIByteArray & ba) {
DWORD wrote[2]; DWORD wrote[2];
int sz = ba.size_s(); int sz = ba.size_s();
WriteFile(pipe, &sz, 4, &(wrote[0]), 0); WriteFile(pipe, &sz, 4, &(wrote[0]), 0);
WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0); WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0);
// piCout << "send" << ba.size_s(); //piCout << "send" << ba.size_s();
return int(wrote[0] + wrote[1]); return int(wrote[0] + wrote[1]);
} }
# endif #endif
PITerminal::PITerminal(): PIThread() { PITerminal::PITerminal(): PIThread() {
@@ -116,42 +114,42 @@ PITerminal::PITerminal(): PIThread() {
initPrivate(); initPrivate();
cursor_blink = false; cursor_blink = false;
cursor_x = cursor_y = 0; cursor_x = cursor_y = 0;
dsize_x = 80; dsize_x = 80;
dsize_y = 24; dsize_y = 24;
# ifdef WINDOWS #ifdef WINDOWS
PRIVATE->shm = 0; PRIVATE->shm = 0;
# endif #endif
} }
PITerminal::~PITerminal() { PITerminal::~PITerminal() {
if (isRunning()) stop(); if (isRunning())
PIThread::waitForFinish(1_s); stop();
PIThread::waitForFinish(10);
destroy(); destroy();
# ifdef WINDOWS #ifdef WINDOWS
if (PRIVATE->shm) delete PRIVATE->shm; if (PRIVATE->shm) delete PRIVATE->shm;
# endif #endif
} }
void PITerminal::write(const PIByteArray & d) { void PITerminal::write(const PIByteArray & d) {
# ifdef WINDOWS #ifdef WINDOWS
PIByteArray msg; PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke; PIVector<PIKbdListener::KeyEvent> ke;
for (int i = 0; i < d.size_s(); ++i) for (int i = 0; i < d.size_s(); ++i)
ke << PIKbdListener::KeyEvent(d[i]); ke << PIKbdListener::KeyEvent(d[i]);
msg << int(mtKey) << ke; msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg); writePipe(PRIVATE->pipe, msg);
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return; if (PRIVATE->fd == 0) return;
// ssize_t wrote = 0; //ssize_t wrote = 0;
// wrote = //wrote =
auto _r = ::write(PRIVATE->fd, d.data(), d.size_s()); ::write(PRIVATE->fd, d.data(), d.size_s());
NO_UNUSED(_r); //piCout << "wrote" << wrote << d;
// piCout << "wrote" << wrote << d;
# endif
# endif # endif
#endif
cursor_tm.reset(); cursor_tm.reset();
cursor_blink = true; cursor_blink = true;
} }
@@ -159,16 +157,15 @@ void PITerminal::write(const PIByteArray & d) {
void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) { void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) {
PIByteArray ba; PIByteArray ba;
# ifdef WINDOWS #ifdef WINDOWS
switch (k) { switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break; case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break; case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break;
case PIKbdListener::Space: ba << uchar(' '); break; case PIKbdListener::Space: ba << uchar(' '); break;
default: break; default: break;
} }
// piCout << "write" << ba.size(); //piCout << "write" << ba.size();
if (!ba.isEmpty()) if (!ba.isEmpty()) write(ba);
write(ba);
else { else {
PIByteArray msg; PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke; PIVector<PIKbdListener::KeyEvent> ke;
@@ -176,20 +173,19 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
msg << int(mtKey) << ke; msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg); writePipe(PRIVATE->pipe, msg);
} }
# else #else
int term = PRIVATE->term_type; int term = PRIVATE->term_type;
int flags = 0; int flags = 0;
switch (k) { switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break; case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\n'); break; case PIKbdListener::Return: ba << uchar('\n'); break;
case PIKbdListener::Esc: ba << uchar('\e'); break; case PIKbdListener::Esc: ba << uchar('\e'); break;
case PIKbdListener::Space: ba << uchar(' '); break; case PIKbdListener::Space: ba << uchar(' '); break;
case PIKbdListener::Backspace: ba << uchar(0x7f); break; case PIKbdListener::Backspace: ba << uchar(0x7f); break;
case PIKbdListener::UpArrow: case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow: case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow: case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow: case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1;
if (PRIVATE->DEC.value(CKM, false)) flags = 1;
/*case PIKbdListener::Home: //break; /*case PIKbdListener::Home: //break;
case PIKbdListener::End: //break; case PIKbdListener::End: //break;
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break; case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
@@ -210,55 +206,55 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::F12: //break; case PIKbdListener::F12: //break;
*/ */
default: { default: {
// piCout << flags; //piCout << flags;
// int mod = 0; //int mod = 0;
if (m[PIKbdListener::Shift]) m |= 1; if (m[PIKbdListener::Shift]) m |= 1;
if (m[PIKbdListener::Alt]) m |= 2; if (m[PIKbdListener::Alt]) m |= 2;
if (m[PIKbdListener::Ctrl]) m |= 4; if (m[PIKbdListener::Ctrl]) m |= 4;
for (int i = 0;; ++i) { for (int i = 0; ; ++i) {
const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]); const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]);
if (!e.seq) break; if (!e.seq) break;
// piCout << "search" << rc[1] << esc_seq[i].seq; //piCout << "search" << rc[1] << esc_seq[i].seq;
if (e.key == k && e.mod == m) { if (e.key == k && e.mod == m) {
if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) { if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) {
// piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e"); //piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e");
PIByteArray d = ("\e" + PIString(e.seq)).toByteArray(); PIByteArray d = ("\e" + PIString(e.seq)).toByteArray();
write(d); write(d);
break; break;
} }
} }
} }
} break; } break;
} }
// piCout << "write" << ba.size(); //piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba); if (!ba.isEmpty()) write(ba);
# endif #endif
cursor_tm.reset(); cursor_tm.reset();
cursor_blink = true; cursor_blink = true;
} }
void PITerminal::write(PIKbdListener::KeyEvent ke) { void PITerminal::write(PIKbdListener::KeyEvent ke) {
if (isSpecialKey(ke.key)) if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
else { else {
PIByteArray ba; PIByteArray ba;
# ifdef WINDOWS #ifdef WINDOWS
ba << uchar(PIChar((ushort)ke.key).toConsole1Byte()); ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
# else #else
ba = PIString(PIChar((ushort)ke.key)).toUTF8(); ba = PIString(PIChar((ushort)ke.key)).toUTF8();
# endif #endif
write(ba); write(ba);
} }
} }
PIVector<PIVector<PIScreenTypes::Cell>> PITerminal::content() { PIVector<PIVector<PIScreenTypes::Cell> > PITerminal::content() {
readConsole(); readConsole();
PIVector<PIVector<PIScreenTypes::Cell>> ret = cells; PIVector<PIVector<PIScreenTypes::Cell> > ret = cells;
if (cursor_blink && cursor_visible) if (cursor_blink && cursor_visible)
if (cursor_x >= 0 && cursor_x < size_x) if (cursor_x >= 0 && cursor_x < size_x)
if (cursor_y >= 0 && cursor_y < size_y) ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse; if (cursor_y >= 0 && cursor_y < size_y)
ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
return ret; return ret;
} }
@@ -299,56 +295,56 @@ bool PITerminal::isSpecialKey(int k) {
void PITerminal::initPrivate() { void PITerminal::initPrivate() {
# ifdef WINDOWS #ifdef WINDOWS
PRIVATE->hConBuf = INVALID_HANDLE_VALUE; PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
PRIVATE->pipe = INVALID_HANDLE_VALUE; PRIVATE->pipe = INVALID_HANDLE_VALUE;
PRIVATE->pi.hProcess = 0; PRIVATE->pi.hProcess = 0;
# else #else
PRIVATE->shell = "/bin/bash"; PRIVATE->shell = "/bin/bash";
PRIVATE->read_buf.reserve(BUFFER_SIZE); PRIVATE->read_buf.reserve(BUFFER_SIZE);
PRIVATE->read_buf.fill(0); PRIVATE->read_buf.fill(0);
PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0; PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0;
PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0; PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0;
PRIVATE->pid = 0; PRIVATE->pid = 0;
PRIVATE->term_type = 0; PRIVATE->term_type = 0;
PRIVATE->is_esc_seq = false; PRIVATE->is_esc_seq = false;
PRIVATE->last_read = true; PRIVATE->last_read = true;
PRIVATE->esc_seq.clear(); PRIVATE->esc_seq.clear();
PRIVATE->cur_format = PIScreenTypes::CellFormat(); PRIVATE->cur_format = PIScreenTypes::CellFormat();
# endif #endif
cursor_blink = cursor_visible = true; cursor_blink = cursor_visible = true;
size_x = size_y = 0; size_x = size_y = 0;
} }
void PITerminal::readConsole() { void PITerminal::readConsole() {
# ifdef WINDOWS #ifdef WINDOWS
if (!PRIVATE->shm) return; if (!PRIVATE->shm) return;
PITerminalAuxData data; PITerminalAuxData data;
PRIVATE->shm->read(&data, sizeof(data)); PRIVATE->shm->read(&data, sizeof(data));
if (data.cells_size <= 4) return; if (data.cells_size <= 4) return;
cursor_x = data.cursor_x; cursor_x = data.cursor_x;
cursor_y = data.cursor_y; cursor_y = data.cursor_y;
size_x = data.size_x; size_x = data.size_x;
size_y = data.size_y; size_y = data.size_y;
PIByteArray ba; PIByteArray ba;
ba.resize(data.cells_size); ba.resize(data.cells_size);
PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data)); PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data));
ba >> cells; ba >> cells;
# endif #endif
// piCout << cursor_x << cursor_y; //piCout << cursor_x << cursor_y;
} }
void PITerminal::getCursor(int & x, int & y) { void PITerminal::getCursor(int & x, int & y) {
# ifdef WINDOWS #ifdef WINDOWS
if (!PRIVATE->shm) return; if (!PRIVATE->shm) return;
int sz = 0; int sz = 0;
PRIVATE->shm->read(&sz, 4); PRIVATE->shm->read(&sz, 4);
# else #else
x = PRIVATE->cur_x; x = PRIVATE->cur_x;
y = PRIVATE->cur_y; y = PRIVATE->cur_y;
# endif #endif
} }
@@ -374,16 +370,16 @@ void PITerminal::run() {
cursor_tm.reset(); cursor_tm.reset();
cursor_blink = !cursor_blink; cursor_blink = !cursor_blink;
} }
# ifndef WINDOWS #ifndef WINDOWS
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return; if (PRIVATE->fd == 0) return;
PRIVATE->tmp_buf.resize(BUFFER_SIZE); PRIVATE->tmp_buf.resize(BUFFER_SIZE);
int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s()); int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s());
bool used = false; bool used = false;
if (readed > 0) { if (readed > 0) {
PRIVATE->last_read = true; PRIVATE->last_read = true;
// piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e"); //piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
// piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed)); //piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed)); PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed));
for (;;) { for (;;) {
int ind = -1; int ind = -1;
@@ -399,27 +395,28 @@ void PITerminal::run() {
} }
bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE; bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE;
if (PRIVATE->read_buf.size_s() == 1) if (PRIVATE->read_buf.size_s() == 1)
if (PRIVATE->read_buf[0] < 0x80) parse = true; if (PRIVATE->read_buf[0] < 0x80)
parse = true;
if (parse) { if (parse) {
parseInput(PIString::fromUTF8(PRIVATE->read_buf)); parseInput(PIString(PRIVATE->read_buf));
PRIVATE->read_buf.clear(); PRIVATE->read_buf.clear();
} }
// printf("%s", PRIVATE->read_buf.data()); //printf("%s", PRIVATE->read_buf.data());
} }
if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) { if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) {
parseInput(PIString::fromUTF8(PRIVATE->read_buf)); parseInput(PIString(PRIVATE->read_buf));
PRIVATE->read_buf.clear(); PRIVATE->read_buf.clear();
} }
PRIVATE->last_read = false; PRIVATE->last_read = false;
# endif
# endif # endif
#endif
} }
# ifndef WINDOWS #ifndef WINDOWS
void PITerminal::parseInput(const PIString & s) { void PITerminal::parseInput(const PIString & s) {
// piCoutObj << s.replaceAll("\e", "\\e"); //piCoutObj << s.replaceAll("\e", "\\e");
// printf("%s", s.data()); //printf("%s", s.data());
for (int i = 0; i < s.size_s(); ++i) { for (int i = 0; i < s.size_s(); ++i) {
if (s[i].unicode16Code() == 0) break; if (s[i].unicode16Code() == 0) break;
if (PRIVATE->is_esc_seq) { if (PRIVATE->is_esc_seq) {
@@ -432,7 +429,7 @@ void PITerminal::parseInput(const PIString & s) {
if (isCompleteEscSeq(PRIVATE->esc_seq)) { if (isCompleteEscSeq(PRIVATE->esc_seq)) {
PRIVATE->is_esc_seq = false; PRIVATE->is_esc_seq = false;
applyEscSeq(PRIVATE->esc_seq); applyEscSeq(PRIVATE->esc_seq);
// piCoutObj << PRIVATE->esc_seq; //piCoutObj << PRIVATE->esc_seq;
} }
} }
} else { } else {
@@ -447,15 +444,14 @@ void PITerminal::parseInput(const PIString & s) {
} }
if (s[i] == '\r') continue; if (s[i] == '\r') continue;
if (s[i] == '\n') { if (s[i] == '\n') {
// piCoutObj << "new line"; //piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
moveCursor(0, 1); moveCursor(0, 1);
continue; continue;
} }
// piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y; //piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y;
cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i]; cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i];
cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format; cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format;
moveCursor(1, 0); moveCursor(1, 0);
@@ -479,10 +475,10 @@ bool PITerminal::isCompleteEscSeq(const PIString & es) {
void PITerminal::applyEscSeq(PIString es) { void PITerminal::applyEscSeq(PIString es) {
piCoutObj << es; piCoutObj << es;
if (es.size_s() < 2) return; if (es.size_s() < 2) return;
// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format); // PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format);
PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format); PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format);
if (es[1] == '?' && es.size_s() >= 2) { if (es[1] == '?' && es.size_s() >= 2) {
char a = es.takeRight(1)[0].toAscii(); char a = es.takeRight(1)[0].toAscii();
bool val = false; bool val = false;
if (a == 'l') val = false; if (a == 'l') val = false;
if (a == 'h') val = true; if (a == 'h') val = true;
@@ -502,8 +498,7 @@ void PITerminal::applyEscSeq(PIString es) {
case 1047: case 1047:
if (val) { if (val) {
PRIVATE->cells_save = cells; PRIVATE->cells_save = cells;
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
cells[i].fill(def_cell);
} else { } else {
cells = PRIVATE->cells_save; cells = PRIVATE->cells_save;
} }
@@ -518,7 +513,7 @@ void PITerminal::applyEscSeq(PIString es) {
return; return;
} }
PIStringList args = es.split(";"); PIStringList args = es.split(";");
for (const auto & a: args) { piForeachC (PIString & a, args) {
int av = a.toInt(); int av = a.toInt();
switch (av) { switch (av) {
case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break; case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break;
@@ -529,14 +524,8 @@ void PITerminal::applyEscSeq(PIString es) {
default: { default: {
bool col = false, target = false; bool col = false, target = false;
int cid = av % 10; int cid = av % 10;
if (av >= 30 && av <= 37) { if (av >= 30 && av <= 37) {col = true; target = false;}
col = true; if (av >= 40 && av <= 47) {col = true; target = true;}
target = false;
}
if (av >= 40 && av <= 47) {
col = true;
target = true;
}
if (col) { if (col) {
int cfl = 0; int cfl = 0;
switch (cid) { switch (cid) {
@@ -555,13 +544,13 @@ void PITerminal::applyEscSeq(PIString es) {
PRIVATE->cur_format.color_char = cfl; PRIVATE->cur_format.color_char = cfl;
break; break;
} }
} break; } break;
} }
} }
/*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) { /*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) {
uchar t = PRIVATE->cur_format.color_char; uchar t = PRIVATE->cur_format.color_char;
PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back; PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back;
PRIVATE->cur_format.color_back = t; PRIVATE->cur_format.color_back = t;
}*/ }*/
} }
if (es.back() == 'r') { if (es.back() == 'r') {
@@ -590,37 +579,33 @@ void PITerminal::applyEscSeq(PIString es) {
int x(0), y(0); int x(0), y(0);
if (!args[0].isEmpty()) y = args[0].toInt() - 1; if (!args[0].isEmpty()) y = args[0].toInt() - 1;
if (!args[1].isEmpty()) x = args[1].toInt() - 1; if (!args[1].isEmpty()) x = args[1].toInt() - 1;
// piCoutObj << x << y; //piCoutObj << x << y;
PRIVATE->cur_x = piClamp(x, 0, size_x - 1); PRIVATE->cur_x = piClamp(x, 0, size_x - 1);
PRIVATE->cur_y = piClamp(y, 0, size_y - 1); PRIVATE->cur_y = piClamp(y, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'A') { // cursor up if (es.back() == 'A') { // cursor up
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'B') { // cursor down if (es.back() == 'B') { // cursor down
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'D') { // cursor back if (es.back() == 'D') { // cursor back
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'G' || es.back() == '`') { // goto column if (es.back() == 'G' || es.back() == '`') { // goto column
@@ -631,92 +616,66 @@ void PITerminal::applyEscSeq(PIString es) {
} }
if (es.back() == 'd') { // goto line if (es.back() == 'd') { // goto line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0; PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'E' || es.back() == 'e') { // next line if (es.back() == 'E' || es.back() == 'e') { // next line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0; PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'F') { // previous line if (es.back() == 'F') { // previous line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0; PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'L') { // insert lines if (es.back() == 'L') { // insert lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); --i) cells[i] = cells[i - v];
for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); ++j)
i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
--i)
cells[i] = cells[i - v];
for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1);
++j)
for (int i = 0; i < PRIVATE->cur_x; ++i)
cells[j][i] = def_cell;
} }
if (es.back() == 'M') { // delete lines if (es.back() == 'M') { // delete lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); ++i) cells[i] = cells[i + v];
for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1);
++i)
cells[i] = cells[i + v];
for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j) for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j)
for (int i = 0; i < PRIVATE->cur_x; ++i) for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
cells[j][i] = def_cell;
} }
if (es.back() == 'P') { // delete characters if (es.back() == 'P') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = PRIVATE->cur_x; i < size_x - v; ++i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v];
for (int i = PRIVATE->cur_x; i < size_x - v; ++i) for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v];
for (int i = size_x - v; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
} }
if (es.back() == '@') { // delete characters if (es.back() == '@') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt(); if (v == 0) v = 1;
if (v == 0) v = 1; for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v];
for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v];
for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
} }
if (es.back() == 'J') { // erase data if (es.back() == 'J') { // erase data
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell; for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell);
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i)
cells[i].fill(def_cell);
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell; for (int i = 0; i < PRIVATE->cur_y; ++i) cells[i].fill(def_cell);
for (int i = 0; i < PRIVATE->cur_y; ++i)
cells[i].fill(def_cell);
break; break;
case 2: case 2:
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
cells[i].fill(def_cell); //PRIVATE->cur_x = PRIVATE->cur_y = 0;
// PRIVATE->cur_x = PRIVATE->cur_y = 0;
break; break;
} }
} }
@@ -725,14 +684,14 @@ void PITerminal::applyEscSeq(PIString es) {
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell;
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
cells[PRIVATE->cur_y][i] = def_cell; break;
case 2:
cells[PRIVATE->cur_y].fill(def_cell);
break; break;
case 2: cells[PRIVATE->cur_y].fill(def_cell); break;
} }
} }
} }
@@ -746,12 +705,12 @@ void PITerminal::moveCursor(int dx, int dy) {
if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0; if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0;
if (PRIVATE->cur_x >= size_x) { if (PRIVATE->cur_x >= size_x) {
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y++; PRIVATE->cur_y++;
} }
if (PRIVATE->cur_y >= size_y) { if (PRIVATE->cur_y >= size_y) {
int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1); int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1);
// piCout << "scroll" << size_x << size_y << size_y - scroll - 1; //piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
PRIVATE->cur_y = size_y - 1; PRIVATE->cur_y = size_y - 1;
for (int y = 0; y < size_y - scroll; ++y) for (int y = 0; y < size_y - scroll; ++y)
cells[y] = cells[y + scroll]; cells[y] = cells[y + scroll];
@@ -762,76 +721,58 @@ void PITerminal::moveCursor(int dx, int dy) {
int PITerminal::termType(const PIString & t) { int PITerminal::termType(const PIString & t) {
if (t == "xterm") if (t == "xterm") return PIKbdListener::vt_xterm;
return PIKbdListener::vt_xterm; else if (t == "linux") return PIKbdListener::vt_linux;
else if (t == "linux")
return PIKbdListener::vt_linux;
return PIKbdListener::vt_none; return PIKbdListener::vt_none;
} }
# endif #endif
bool PITerminal::initialize() { bool PITerminal::initialize() {
destroy(); destroy();
# ifdef WINDOWS #ifdef WINDOWS
/*SECURITY_ATTRIBUTES sa; /*SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true; sa.bInheritHandle = true;
sa.lpSecurityDescriptor = 0; sa.lpSecurityDescriptor = 0;
if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) { if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) {
piCoutObj << "CreatePipe error," << errorString(); piCoutObj << "CreatePipe error," << errorString();
initPrivate(); initPrivate();
return false; return false;
} }
PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0); PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0);
if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) { if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateConsoleScreenBuffer error," << errorString(); piCoutObj << "CreateConsoleScreenBuffer error," << errorString();
destroy(); destroy();
return false; return false;
}*/ }*/
// CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0); //CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
// SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0); //SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
// SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0); //SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
// GetStartupInfoA(&PRIVATE->si); //GetStartupInfoA(&PRIVATE->si);
piZeroMemory(PRIVATE->si); memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
PRIVATE->si.cb = sizeof(STARTUPINFO); PRIVATE->si.cb = sizeof(STARTUPINFO);
// PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES; //PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW; PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS; PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS;
// PRIVATE->si.hStdInput = PRIVATE->pipe; //PRIVATE->si.hStdInput = PRIVATE->pipe;
// PRIVATE->si.hStdOutput = PRIVATE->hConBuf; //PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
// PRIVATE->si.hStdError = PRIVATE->hConBuf; //PRIVATE->si.hStdError = PRIVATE->hConBuf;
PRIVATE->si.wShowWindow = SW_HIDE; PRIVATE->si.wShowWindow = SW_HIDE;
PRIVATE->si.dwXCountChars = 80; PRIVATE->si.dwXCountChars = 80;
PRIVATE->si.dwYCountChars = 24; PRIVATE->si.dwYCountChars = 24;
piZeroMemory(PRIVATE->pi); memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi));
PIString shmh = PIString::fromNumber(randomi() % 10000); PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString pname = "\\\\.\\pipe\\piterm" + shmh; PIString pname = "\\\\.\\pipe\\piterm" + shmh;
PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\""; PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
if (!CreateProcessA(0, if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) {
(LPSTR)cmd.dataAscii(),
0,
0,
false,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
0,
0,
&PRIVATE->si,
&PRIVATE->pi)) {
piCoutObj << "CreateProcess error," << errorString(); piCoutObj << "CreateProcess error," << errorString();
destroy(); destroy();
return false; return false;
} }
PRIVATE->pipe = CreateNamedPipeA((LPSTR)pname.dataAscii(), PRIVATE->pipe = CreateNamedPipe((LPSTR)pname.dataAscii(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 1000, NULL);
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
2,
PIPE_BUFFER_SIZE,
PIPE_BUFFER_SIZE,
1000,
NULL);
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) { if (PRIVATE->pipe == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateNamedPipe error," << errorString(); piCoutObj << "CreateNamedPipe error," << errorString();
destroy(); destroy();
@@ -851,32 +792,31 @@ bool PITerminal::initialize() {
return false; return false;
} }
if (PRIVATE->shm) delete PRIVATE->shm; if (PRIVATE->shm) delete PRIVATE->shm;
PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024 * 1024); PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024*1024);
CloseHandle(PRIVATE->pi.hThread); CloseHandle(PRIVATE->pi.hThread);
resize(dsize_x, dsize_y); resize(dsize_x, dsize_y);
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
char pty[256]; char pty[256]; memset(pty, 0, 256);
piZeroMemory(pty, 256);
winsize ws; winsize ws;
ws.ws_col = dsize_x; ws.ws_col = dsize_x;
ws.ws_row = dsize_y; ws.ws_row = dsize_y;
PIStringList env = PIProcess::currentEnvironment(); PIStringList env = PIProcess::currentEnvironment();
for (const auto & e: env) piForeachC (PIString & e, env)
if (e.startsWith("TERM=")) { if (e.startsWith("TERM=")) {
PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase()); PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase());
// piCout << PRIVATE->term_type; //piCout << PRIVATE->term_type;
break; break;
} }
pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws); pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws);
// piCoutObj << fr << PRIVATE->fd << pty; //piCoutObj << fr << PRIVATE->fd << pty;
if (fr == 0) { if (fr == 0) {
char ** argv = new char *[2]; char ** argv = new char*[2];
PIByteArray shell = PRIVATE->shell.toByteArray(); PIByteArray shell = PRIVATE->shell.toByteArray();
argv[0] = new char[shell.size() + 1]; argv[0] = new char[shell.size() + 1];
memcpy(argv[0], shell.data(), shell.size()); memcpy(argv[0], shell.data(), shell.size());
argv[0][shell.size()] = 0; argv[0][shell.size()] = 0;
argv[1] = 0; argv[1] = 0;
execvp(argv[0], argv); execvp(argv[0], argv);
delete[] argv[0]; delete[] argv[0];
delete[] argv; delete[] argv;
@@ -889,77 +829,79 @@ bool PITerminal::initialize() {
} }
PRIVATE->pid = fr; PRIVATE->pid = fr;
fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK); fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK);
/* /*
tcgetattr(PRIVATE->fd, &PRIVATE->desc); tcgetattr(PRIVATE->fd, &PRIVATE->desc);
PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0; PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0;
PRIVATE->desc.c_iflag = IGNBRK; PRIVATE->desc.c_iflag = IGNBRK;
PRIVATE->desc.c_cflag = CLOCAL | HUPCL; PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
PRIVATE->desc.c_cflag |= (CSIZE & CS8); PRIVATE->desc.c_cflag |= (CSIZE & CS8);
PRIVATE->desc.c_cflag |= CREAD; PRIVATE->desc.c_cflag |= CREAD;
PRIVATE->desc.c_cc[VMIN] = 1; PRIVATE->desc.c_cc[VMIN] = 1;
PRIVATE->desc.c_cc[VTIME] = 1; PRIVATE->desc.c_cc[VTIME] = 1;
cfsetispeed(&PRIVATE->desc, B38400); cfsetispeed(&PRIVATE->desc, B38400);
cfsetospeed(&PRIVATE->desc, B38400); cfsetospeed(&PRIVATE->desc, B38400);
if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) { if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) {
piCoutObj << "Can`t set attributes for \"" << pty << "\""; piCoutObj << "Can`t set attributes for \"" << pty << "\"";
destroy(); destroy();
return false; return false;
} }
*/ */
size_x = dsize_x; size_x = dsize_x;
size_y = dsize_y; size_y = dsize_y;
resize(size_x, size_y); resize(size_x, size_y);
} }
# endif
# endif # endif
#endif
cursor_blink = false; cursor_blink = false;
cursor_tm.reset(); cursor_tm.reset();
start(25_Hz); start(40);
return true; return true;
} }
void PITerminal::destroy() { void PITerminal::destroy() {
// piCout << "destroy ..."; //piCout << "destroy ...";
stop(); stop();
waitForFinish(1_s); waitForFinish(1000);
# ifdef WINDOWS #ifdef WINDOWS
if (PRIVATE->pi.hProcess) { if (PRIVATE->pi.hProcess) {
// piCout << "term"; //piCout << "term";
// TerminateProcess(PRIVATE->pi.hProcess, 0); //TerminateProcess(PRIVATE->pi.hProcess, 0);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId); GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId);
CloseHandle(PRIVATE->pi.hProcess); CloseHandle(PRIVATE->pi.hProcess);
} }
if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe); if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe);
if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf); if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf);
// piCout << "destroy" << size_y; //piCout << "destroy" << size_y;
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL); if (PRIVATE->pid != 0)
if (PRIVATE->fd != 0) ::close(PRIVATE->fd); kill(PRIVATE->pid, SIGKILL);
# endif if (PRIVATE->fd != 0)
::close(PRIVATE->fd);
# endif # endif
#endif
initPrivate(); initPrivate();
} }
bool PITerminal::resize(int cols, int rows) { bool PITerminal::resize(int cols, int rows) {
bool ret = true; bool ret = true;
dsize_x = cols; dsize_x = cols;
dsize_y = rows; dsize_y = rows;
# ifdef WINDOWS #ifdef WINDOWS
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false; if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false;
PIByteArray msg; PIByteArray msg;
msg << int(mtResize) << dsize_x << dsize_y; msg << int(mtResize) << dsize_x << dsize_y;
writePipe(PRIVATE->pipe, msg); writePipe(PRIVATE->pipe, msg);
# else #else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return false; if (PRIVATE->fd == 0) return false;
size_x = dsize_x; size_x = dsize_x;
size_y = dsize_y; size_y = dsize_y;
// piCout << "resize" << PRIVATE->fd << size_x << size_y; //piCout << "resize" << PRIVATE->fd << size_x << size_y;
winsize ws; winsize ws;
ws.ws_col = cols; ws.ws_col = cols;
ws.ws_row = rows; ws.ws_row = rows;
@@ -969,8 +911,8 @@ bool PITerminal::resize(int cols, int rows) {
PRIVATE->cells_save.resize(size_y); PRIVATE->cells_save.resize(size_y);
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i)
PRIVATE->cells_save[i].resize(size_x); PRIVATE->cells_save[i].resize(size_x);
# endif
# endif # endif
#endif
cells.resize(size_y); cells.resize(size_y);
for (int i = 0; i < size_y; ++i) for (int i = 0; i < size_y; ++i)
cells[i].resize(size_x); cells[i].resize(size_x);

View File

@@ -1,297 +1,297 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PIP Authentication API PIP Authentication API
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piauth.h" #include "piauth.h"
#define PIAUTH_NOISE_MAX_SIZE 256 #define PIAUTH_NOISE_MAX_SIZE 256
PIAuth::PIAuth(const PIByteArray & sign): PIObject() { PIAuth::PIAuth(const PIByteArray & sign) : PIObject() {
setName("Client"); setName("Client");
role = Client; role = Client;
state = NotConnected; state = NotConnected;
sign_sk = sign; sign_sk = sign;
sign_pk = crypt.extractSignPublicKey(sign); sign_pk = crypt.extractSignPublicKey(sign);
} }
void PIAuth::setServerPassword(const PIString & ps) { void PIAuth::setServerPassword(const PIString & ps) {
pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray()); pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
} }
void PIAuth::stop() { void PIAuth::stop() {
role = Client; role = Client;
state = NotConnected; state = NotConnected;
auth_sign.clear(); auth_sign.clear();
box_sk.clear(); box_sk.clear();
box_pk.clear(); box_pk.clear();
my_pk.clear(); my_pk.clear();
} }
void PIAuth::startClient() { void PIAuth::startClient() {
role = Client; role = Client;
state = AuthProbe; state = AuthProbe;
} }
PIByteArray PIAuth::startServer() { PIByteArray PIAuth::startServer() {
setName("Server"); setName("Server");
role = Server; role = Server;
state = AuthProbe; state = AuthProbe;
PIByteArray ba; PIByteArray ba;
crypt.generateKeypair(my_pk, box_sk); crypt.generateKeypair(my_pk, box_sk);
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE + 128); PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE+128);
ba << (int)state << custom_info << sign_pk << my_pk << noise; ba << (int)state << custom_info << sign_pk << my_pk << noise;
PIByteArray sign = crypt.signMessage(ba, sign_sk); PIByteArray sign = crypt.signMessage(ba, sign_sk);
ba << sign; ba << sign;
return ba; return ba;
} }
PIAuth::State PIAuth::receive(PIByteArray & ba) { PIAuth::State PIAuth::receive(PIByteArray & ba) {
if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size"); if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size");
State rstate; State rstate;
int s; int s;
ba >> s; ba >> s;
rstate = (State)s; rstate = (State)s;
// if (state != rstate) return disconect(ba); // if (state != rstate) return disconect(ba);
// client side //client side
if (role == Client) { if (role == Client) {
if (state == AuthProbe && rstate == AuthProbe) { if (state == AuthProbe && rstate == AuthProbe) {
if (ba.size() < sizeof(int) * 5) return disconnect(ba, "invalid data size"); if (ba.size() < sizeof(int)*5) return disconnect(ba, "invalid data size");
PIByteArray rinfo; PIByteArray rinfo;
PIByteArray rsign; PIByteArray rsign;
PIByteArray rsign_pk; PIByteArray rsign_pk;
PIByteArray noise; PIByteArray noise;
ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign; ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign;
if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size"); if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size");
PIByteArray tba; PIByteArray tba;
tba << (int)rstate << rinfo << rsign_pk << box_pk << noise; tba << (int)rstate << rinfo << rsign_pk << box_pk << noise;
if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign");
bool auth = false; bool auth = false;
if (isAuthorizedKey(rsign_pk)) { if (isAuthorizedKey(rsign_pk)) {
auth = true; auth = true;
} else { } else {
authorize(rinfo, &auth); authorize(rinfo, &auth);
if (auth) auth_pkeys << rsign_pk; if (auth) auth_pkeys << rsign_pk;
} }
if (!auth) return disconnect(ba, "Unauthorised"); if (!auth) return disconnect(ba, "Unauthorised");
ba.clear(); ba.clear();
auth_sign = rsign_pk; auth_sign = rsign_pk;
crypt.generateKeypair(my_pk, box_sk); crypt.generateKeypair(my_pk, box_sk);
tba.clear(); tba.clear();
tba << sign_pk << my_pk << box_pk; tba << sign_pk << my_pk << box_pk;
PIByteArray sign = crypt.signMessage(tba, sign_sk); PIByteArray sign = crypt.signMessage(tba, sign_sk);
tba << sign; tba << sign;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
state = AuthReply; state = AuthReply;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << tba << my_pk << noise; ba << (int)state << tba << my_pk << noise;
sign = crypt.signMessage(ba, sign_sk); sign = crypt.signMessage(ba, sign_sk);
ba << sign; ba << sign;
return state; return state;
} }
if (state == AuthReply && rstate == PassRequest) { if (state == AuthReply && rstate == PassRequest) {
PIByteArray ctba, tba; PIByteArray ctba, tba;
PIByteArray noise; PIByteArray noise;
PIByteArray rsign, rsign_pk; PIByteArray rsign, rsign_pk;
ba >> ctba >> rsign; ba >> ctba >> rsign;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear(); ba.clear();
ba << (int)rstate << ctba; ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear(); ctba.clear();
tba >> rsign_pk >> noise >> ctba; tba >> rsign_pk >> noise >> ctba;
if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key"); if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key");
PIString ps; PIString ps;
PIByteArray ph; PIByteArray ph;
passwordRequest(&ps); passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user"); if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray()); ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar()); ps.fill(PIChar());
tba.clear(); tba.clear();
tba << ph << auth_sign << sign_pk; tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
ba.clear(); ba.clear();
state = PassRequest; state = PassRequest;
ba << (int)state << tba; ba << (int)state << tba;
rsign = crypt.signMessage(ba, sign_sk); rsign = crypt.signMessage(ba, sign_sk);
ba << rsign; ba << rsign;
return state; return state;
} }
if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) { if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) {
PIByteArray tba, ctba; PIByteArray tba, ctba;
PIByteArray rsign; PIByteArray rsign;
ba >> ctba >> rsign; ba >> ctba >> rsign;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear(); ba.clear();
ba << (int)rstate << ctba; ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
tba >> secret_key; tba >> secret_key;
if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key"); if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key");
ba.clear(); ba.clear();
state = Connected; state = Connected;
connected(PIString()); connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }
if (state == Connected && rstate == Connected) { if (state == Connected && rstate == Connected) {
ba.clear(); ba.clear();
state = Connected; state = Connected;
connected(PIString()); connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }
} }
// server side // server side
if (role == Server) { if (role == Server) {
if (state == AuthProbe && rstate == AuthReply) { if (state == AuthProbe && rstate == AuthReply) {
if (ba.size() < sizeof(int) * 4) return disconnect(ba, "invalid data size"); if (ba.size() < sizeof(int)*4) return disconnect(ba, "invalid data size");
PIByteArray ctba, tba; PIByteArray ctba, tba;
PIByteArray noise; PIByteArray noise;
PIByteArray rsign1, rsign2; PIByteArray rsign1, rsign2;
PIByteArray rsign_pk; PIByteArray rsign_pk;
PIByteArray pk, mpk; PIByteArray pk, mpk;
ba >> ctba >> pk >> noise >> rsign1; ba >> ctba >> pk >> noise >> rsign1;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, pk, box_sk, &ok); tba = crypt.decrypt(ctba, pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
if (tba.size() < sizeof(int) * 3) return disconnect(tba, "invalid data size"); if (tba.size() < sizeof(int)*3) return disconnect(tba, "invalid data size");
tba >> rsign_pk >> box_pk >> mpk >> rsign2; tba >> rsign_pk >> box_pk >> mpk >> rsign2;
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key"); if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
ba.clear(); ba.clear();
ba << (int)rstate << ctba << box_pk << noise; ba << (int)rstate << ctba << box_pk << noise;
if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign");
ba.clear(); ba.clear();
ba << rsign_pk << box_pk << my_pk; ba << rsign_pk << box_pk << my_pk;
if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign");
auth_sign = rsign_pk; auth_sign = rsign_pk;
if (isAuthorizedKey(rsign_pk)) { if (isAuthorizedKey(rsign_pk)) {
state = KeyExchange; state = KeyExchange;
ba = createSKMessage(); ba = createSKMessage();
return state; return state;
} else { } else {
ba.clear(); ba.clear();
tba.clear(); tba.clear();
state = PassRequest; state = PassRequest;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << sign_pk << noise << box_pk; tba << sign_pk << noise << box_pk;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
ba << (int)state << tba; ba << (int)state << tba;
rsign1 = crypt.signMessage(ba, sign_sk); rsign1 = crypt.signMessage(ba, sign_sk);
ba << rsign1; ba << rsign1;
return state; return state;
} }
} }
if (state == PassRequest && rstate == PassRequest) { if (state == PassRequest && rstate == PassRequest) {
PIByteArray tba, ctba; PIByteArray tba, ctba;
PIByteArray rsign_pk, rsign, mpk; PIByteArray rsign_pk, rsign, mpk;
ba >> ctba >> rsign; ba >> ctba >> rsign;
bool ok = false; bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok); tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted"); if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear(); ba.clear();
ba << (int)rstate << ctba; ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign"); if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear(); ctba.clear();
tba >> ctba >> mpk >> rsign_pk; tba >> ctba >> mpk >> rsign_pk;
if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key"); if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key");
bool auth = (ctba == pass_hash); bool auth = (ctba == pass_hash);
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false; if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
passwordCheck(auth); passwordCheck(auth);
if (!auth) { if (!auth) {
// piSleep(1); // piSleep(1);
return disconnect(ba, "Invalid password"); return disconnect(ba, "Invalid password");
} }
state = KeyExchange; state = KeyExchange;
ba = createSKMessage(); ba = createSKMessage();
return state; return state;
} }
if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) { if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) {
ba.clear(); ba.clear();
PIByteArray rinfo; PIByteArray rinfo;
ba >> rinfo; ba >> rinfo;
bool ok = false; bool ok = false;
rinfo = crypt.decrypt(rinfo, secret_key, &ok); rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys"); if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected; state = Connected;
connected(PIString::fromUTF8(rinfo)); connected(rinfo);
ba << (int)state << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }
} }
return disconnect(ba, "invalid state " + PIString::fromNumber((int)state)); return disconnect(ba, "invalid state " + PIString::fromNumber((int)state));
} }
PIByteArray PIAuth::getSecretKey() { PIByteArray PIAuth::getSecretKey() {
if (state == Connected) return secret_key; if (state == Connected) return secret_key;
return PIByteArray(); return PIByteArray();
} }
PIByteArray PIAuth::generateSign(const PIByteArray & seed) { PIByteArray PIAuth::generateSign(const PIByteArray & seed) {
PIByteArray pk, sk; PIByteArray pk, sk;
PICrypt::generateSignKeys(pk, sk, seed); PICrypt::generateSignKeys(pk, sk, seed);
return sk; return sk;
} }
PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) { PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
if (!error.isEmpty()) piCoutObj << error; if (!error.isEmpty()) piCoutObj << error;
auth_sign.clear(); auth_sign.clear();
box_sk.clear(); box_sk.clear();
box_pk.clear(); box_pk.clear();
my_pk.clear(); my_pk.clear();
secret_key.clear(); secret_key.clear();
ba.clear(); ba.clear();
state = NotConnected; state = NotConnected;
disconnected(error); disconnected(error);
return state; return state;
} }
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) { bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
for (int i = 0; i < auth_pkeys.size_s(); ++i) { for (int i=0; i<auth_pkeys.size_s(); ++i) {
if (pkey == auth_pkeys[i]) return true; if (pkey == auth_pkeys[i]) return true;
} }
return false; return false;
} }
PIByteArray PIAuth::createSKMessage() { PIByteArray PIAuth::createSKMessage() {
secret_key = crypt.generateKey(); secret_key = crypt.generateKey();
PIByteArray tba; PIByteArray tba;
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << secret_key << noise; tba << secret_key << noise;
tba = crypt.crypt(tba, box_pk, box_sk); tba = crypt.crypt(tba, box_pk, box_sk);
PIByteArray ret; PIByteArray ret;
ret << (int)state << tba; ret << (int)state << tba;
PIByteArray sign = crypt.signMessage(ret, sign_sk); PIByteArray sign = crypt.signMessage(ret, sign_sk);
ret << sign; ret << sign;
return ret; return ret;
} }

View File

@@ -1,376 +1,448 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Cryptographic class using lib Sodium Cryptographic class using lib Sodium
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "picrypt.h" #include "picrypt.h"
#ifdef PIP_CRYPT
#include "pitranslator.h" # include <sodium.h>
#include <sodium.h> #endif
#define PICRYPT_DISABLED_WARNING piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
namespace {
constexpr char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0"; const char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
constexpr int hash_def_key_size = 9; const int hash_def_key_size = 9;
} // namespace
PICrypt::PICrypt() {
PICrypt::PICrypt() { #ifdef PIP_CRYPT
if (!init()) { if (!init()) piCout << "[PICrypt]" << "Error while initialize sodium!";
piCout << "[PICrypt]" nonce_.resize(crypto_secretbox_NONCEBYTES);
<< "Error while initialize sodium!"_tr("PICrypt"); key_.resize(crypto_secretbox_KEYBYTES);
} randombytes_buf(key_.data(), key_.size());
nonce_.resize(crypto_secretbox_NONCEBYTES); randombytes_buf(nonce_.data(), nonce_.size());
key_.resize(crypto_secretbox_KEYBYTES); #else
randombytes_buf(key_.data(), key_.size()); PICRYPT_DISABLED_WARNING
randombytes_buf(nonce_.data(), nonce_.size()); #endif
} }
PICrypt::~PICrypt() {
key_.fill(0); bool PICrypt::setKey(const PIByteArray & _key) {
nonce_.fill(0); if (_key.size() != key_.size()) return false;
} key_ = _key;
return true;
}
bool PICrypt::setKey(const PIByteArray & _key) {
if (_key.size() != key_.size()) return false;
key_ = _key; PIByteArray PICrypt::setKey(const PIString & secret) {
return true; PIByteArray hash;
} #ifdef PIP_CRYPT
hash.resize(crypto_generichash_BYTES);
PIByteArray s(secret.data(), secret.size());
bool PICrypt::setKey(const PIString & secret) {; crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar*)hash_def_key, hash_def_key_size);
key_ = hash(secret); hash.resize(key_.size());
return key_.isNotEmpty(); setKey(hash);
} #endif
return hash;
}
PIByteArray PICrypt::crypt(const PIByteArray & data) {
PIByteArray ret;
ret.resize(data.size() + crypto_secretbox_MACBYTES); PIByteArray PICrypt::crypt(const PIByteArray & data) {
randombytes_buf(nonce_.data(), nonce_.size()); PIByteArray ret;
if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data()) != 0) { #ifdef PIP_CRYPT
ret.clear(); ret.resize(data.size() + crypto_secretbox_MACBYTES);
} else { randombytes_buf(nonce_.data(), nonce_.size());
ret.append(nonce_); crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data());
} ret.append(nonce_);
return ret; #endif
} return ret;
}
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
if (!init()) { PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
key.fill(0); PIByteArray ret;
return PIByteArray(); #ifdef PIP_CRYPT
} if (key.size() != crypto_secretbox_KEYBYTES)
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' '); key.resize(crypto_secretbox_KEYBYTES, ' ');
PIByteArray n; //return PIByteArray();
n.resize(crypto_secretbox_NONCEBYTES); if (!init()) return ret;
PIByteArray ret; PIByteArray n;
ret.resize(data.size() + crypto_secretbox_MACBYTES); ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(n.data(), n.size()); n.resize(crypto_secretbox_NONCEBYTES);
if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data()) != 0) { randombytes_buf(n.data(), n.size());
ret.clear(); crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data());
} else { ret.append(n);
ret.append(n); #else
} PICRYPT_DISABLED_WARNING
key.fill(0); #endif
return ret; return ret;
} }
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool *ok) {
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) { PIByteArray ret;
if (ok) *ok = false; #ifdef PIP_CRYPT
return PIByteArray(); if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
} if (ok) *ok = false;
const ullong data_size = crypt_data.size() - nonce_.size(); return PIByteArray();
PIByteArray ret; }
ret.resize(data_size - crypto_secretbox_MACBYTES); ret.resize(crypt_data.size() - nonce_.size() - crypto_secretbox_MACBYTES);
memcpy(nonce_.data(), crypt_data.data(data_size), nonce_.size()); memcpy(nonce_.data(), crypt_data.data(crypt_data.size() - nonce_.size()), nonce_.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, nonce_.data(), key_.data()) != 0) { if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - nonce_.size(), nonce_.data(), key_.data()) != 0) {
// Bad key if (ok) *ok = false;
if (ok) *ok = false; // piCout << "[PICrypt]" << "bad key_";
ret.clear(); return PIByteArray();
} else if (ok) { }
*ok = true; #endif
} if (ok) *ok = true;
return ret; return ret;
} }
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool *ok) {
if (!init()) { PIByteArray ret;
key.fill(0); #ifdef PIP_CRYPT
return PIByteArray(); if (key.size() != crypto_secretbox_KEYBYTES)
} key.resize(crypto_secretbox_KEYBYTES, ' ');
if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) { /*if (ok) *ok = false;
if (ok) *ok = false; return PIByteArray();
key.fill(0); }*/
return PIByteArray(); if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) {
} if (ok) *ok = false;
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' '); return PIByteArray();
PIByteArray n; }
n.resize(crypto_secretbox_NONCEBYTES); if (!init()) return ret;
const ullong data_size = crypt_data.size() - n.size(); PIByteArray n;
PIByteArray ret; n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(data_size - crypto_secretbox_MACBYTES); ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size()); memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), key.data()) != 0) { if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) {
// Bad key if (ok) *ok = false;
if (ok) *ok = false; // piCout << "[PICrypt]" << "bad key_";
ret.clear(); return PIByteArray();
} else if (ok) { } else if (ok) *ok = true;
*ok = true; #else
} PICRYPT_DISABLED_WARNING
key.fill(0); #endif
return ret; return ret;
} }
PIByteArray PICrypt::hash(PIString secret) { PIByteArray PICrypt::hash(const PIString & secret) {
if (!init()) return {}; PIByteArray hash;
PIByteArray s = secret.toUTF8(); #ifdef PIP_CRYPT
PIByteArray h = hash(s); if (!init()) return hash;
memset(const_cast<char *>(secret.data()), 0, s.size()); hash.resize(crypto_generichash_BYTES);
secret.fill('\0'); PIByteArray s(secret.data(), secret.size());
s.fill(0); crypto_generichash(hash.data(), hash.size(), s.data(), s.size(),(const uchar*)hash_def_key, hash_def_key_size);
return h; #else
} PICRYPT_DISABLED_WARNING
#endif
return hash;
PIByteArray PICrypt::hash(const PIByteArray & data) { }
if (!init()) return {};
PIByteArray h;
h.resize(crypto_generichash_BYTES); PIByteArray PICrypt::hash(const PIByteArray & data) {
crypto_generichash(h.data(), h.size(), data.data(), data.size(), (const uchar *)hash_def_key, hash_def_key_size); PIByteArray hash;
return h; #ifdef PIP_CRYPT
} if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), (const uchar*)hash_def_key, hash_def_key_size);
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char * key, size_t keylen) { #else
PIByteArray hash; PICRYPT_DISABLED_WARNING
if (!init()) return hash; #endif
hash.resize(crypto_generichash_BYTES); return hash;
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen); }
return hash;
}
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char *key, size_t keylen) {
PIByteArray hash;
size_t PICrypt::sizeHash() { #ifdef PIP_CRYPT
return crypto_generichash_BYTES; if (!init()) return hash;
} hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen);
#else
ullong PICrypt::shorthash(const PIString & s, PIByteArray key) { PICRYPT_DISABLED_WARNING
ullong hash = 0; #endif
if (!init()) { return hash;
key.fill(0); }
return hash;
}
if (crypto_shorthash_BYTES != sizeof(hash)) size_t PICrypt::sizeHash() {
piCout << "[PICrypt]" #ifdef PIP_CRYPT
<< "internal error: bad hash size"_tr("PICrypt"); return crypto_generichash_BYTES;
if (key.size() != crypto_shorthash_KEYBYTES) { #else
piCout << "[PICrypt]" PICRYPT_DISABLED_WARNING
<< "invalid key size %1, should be %2, filled with zeros"_tr("PICrypt").arg(key.size()).arg(crypto_shorthash_KEYBYTES); #endif
key.resize(crypto_shorthash_KEYBYTES, 0); return 0;
} }
PIByteArray in(s.data(), s.size());
crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
key.fill(0); ullong PICrypt::shorthash(const PIString& s, PIByteArray key) {
return hash; ullong hash = 0;
} #ifdef PIP_CRYPT
if (crypto_shorthash_BYTES != sizeof(hash)) piCout << "[PICrypt]" << "internal error: bad hash size";
if (!init()) return hash;
PIByteArray PICrypt::generateKey() { if (key.size() != crypto_shorthash_KEYBYTES) {
return generateRandomBuff(sizeKey()); piCout << "[PICrypt]" << "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
} key.resize(crypto_shorthash_KEYBYTES, 0);
}
PIByteArray in(s.data(), s.size());
PIByteArray PICrypt::generateRandomBuff(int size) { crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
PIByteArray hash; #else
if (!init() || size <= 0) return hash; PICRYPT_DISABLED_WARNING
hash.resize(size); #endif
randombytes_buf(hash.data(), hash.size()); return hash;
return hash; }
}
PIByteArray PICrypt::generateKey() {
size_t PICrypt::sizeKey() { PIByteArray hash;
return crypto_secretbox_KEYBYTES; #ifdef PIP_CRYPT
} if (!init()) return hash;
hash.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(hash.data(), hash.size());
size_t PICrypt::sizeCrypt() { #else
return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; PICRYPT_DISABLED_WARNING
} #endif
return hash;
}
bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
if (!init()) return false;
public_key.resize(crypto_sign_PUBLICKEYBYTES); PIByteArray PICrypt::generateRandomBuff(int size) {
secret_key.resize(crypto_sign_SECRETKEYBYTES); PIByteArray hash;
return crypto_sign_keypair(public_key.data(), secret_key.data()) == 0; #ifdef PIP_CRYPT
} if (!init() || size <= 0) return hash;
hash.resize(size);
randombytes_buf(hash.data(), hash.size());
bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { #else
if (!init() || seed.isEmpty()) return false; PICRYPT_DISABLED_WARNING
public_key.resize(crypto_sign_PUBLICKEYBYTES); #endif
secret_key.resize(crypto_sign_SECRETKEYBYTES); return hash;
return crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0; }
}
size_t PICrypt::sizeKey() {
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) { #ifdef PIP_CRYPT
PIByteArray pk; return crypto_secretbox_KEYBYTES;
if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk; #else
pk.resize(crypto_sign_PUBLICKEYBYTES); PICRYPT_DISABLED_WARNING
if (crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data()) != 0) { #endif
pk.clear(); return 0;
} }
return pk;
}
size_t PICrypt::sizeCrypt() {
#ifdef PIP_CRYPT
PIByteArray PICrypt::signMessage(const PIByteArray & data, const PIByteArray & secret_key) { return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
PIByteArray sign; #else
if (!init()) return sign; PICRYPT_DISABLED_WARNING
sign.resize(crypto_sign_BYTES); #endif
if (crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data()) != 0) { return 0;
sign.clear(); }
}
return sign;
} void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, const PIByteArray & public_key) { public_key.resize(crypto_sign_PUBLICKEYBYTES);
if (!init()) return false; secret_key.resize(crypto_sign_SECRETKEYBYTES);
return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0); crypto_sign_keypair(public_key.data(), secret_key.data());
return false; #else
} PICRYPT_DISABLED_WARNING
#endif
}
bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
if (!init()) return false;
public_key.resize(crypto_box_PUBLICKEYBYTES); void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
secret_key.resize(crypto_box_SECRETKEYBYTES); #ifdef PIP_CRYPT
return crypto_box_keypair(public_key.data(), secret_key.data()) == 0; if (!init() || seed.isEmpty()) return;
} public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { #else
if (!init()) return false; PICRYPT_DISABLED_WARNING
public_key.resize(crypto_box_PUBLICKEYBYTES); #endif
secret_key.resize(crypto_box_SECRETKEYBYTES); }
return crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0;
}
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) {
PIByteArray pk;
PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) { #ifdef PIP_CRYPT
if (!init()) return PIByteArray(); if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) return PIByteArray(); pk.resize(crypto_sign_PUBLICKEYBYTES);
if (secret_key.size() != crypto_box_SECRETKEYBYTES) return PIByteArray(); crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data());
PIByteArray n; #else
n.resize(crypto_box_NONCEBYTES); PICRYPT_DISABLED_WARNING
PIByteArray ret; #endif
ret.resize(data.size() + crypto_box_MACBYTES); return pk;
randombytes_buf(n.data(), n.size()); }
if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
return PIByteArray();
} PIByteArray PICrypt::signMessage(const PIByteArray & data, PIByteArray secret_key) {
ret.append(n); PIByteArray sign;
return ret; #ifdef PIP_CRYPT
} if (!init()) return sign;
sign.resize(crypto_sign_BYTES);
crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data());
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) { #else
if (!init()) { PICRYPT_DISABLED_WARNING
if (ok) *ok = false; #endif
return PIByteArray(); return sign;
} }
if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
if (ok) *ok = false;
return PIByteArray(); bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key) {
} #ifdef PIP_CRYPT
if (secret_key.size() != crypto_box_SECRETKEYBYTES) { if (!init()) return false;
if (ok) *ok = false; return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0);
return PIByteArray(); #else
} PICRYPT_DISABLED_WARNING
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) { #endif
if (ok) *ok = false; return false;
return PIByteArray(); }
}
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES); void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
const ullong data_size = crypt_data.size() - n.size(); #ifdef PIP_CRYPT
PIByteArray ret; if (!init()) return;
ret.resize(data_size - crypto_secretbox_MACBYTES); public_key.resize(crypto_box_PUBLICKEYBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size()); secret_key.resize(crypto_box_SECRETKEYBYTES);
if (crypto_box_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), public_key.data(), secret_key.data()) != 0) { crypto_box_keypair(public_key.data(), secret_key.data());
// Bad key #else
if (ok) *ok = false; PICRYPT_DISABLED_WARNING
ret.clear(); #endif
} else if (ok) { }
*ok = true;
}
return ret; void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
} #ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
PIByteArray PICrypt::passwordHash(PIString password, const PIByteArray & seed) { secret_key.resize(crypto_box_SECRETKEYBYTES);
#ifdef crypto_pwhash_ALG_ARGON2I13 crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
PIByteArray pass = password.toUTF8(); #else
PIByteArray n = hash(seed); PICRYPT_DISABLED_WARNING
PIByteArray ph; #endif
ph.resize(crypto_box_SEEDBYTES); }
n.resize(crypto_pwhash_SALTBYTES);
int r = crypto_pwhash(ph.data(),
ph.size(), PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) {
(const char *)pass.data(), PIByteArray ret;
pass.size(), #ifdef PIP_CRYPT
n.data(), if (!init()) return ret;
crypto_pwhash_argon2i_opslimit_moderate(), if (public_key.size() != crypto_box_PUBLICKEYBYTES)
crypto_pwhash_argon2i_memlimit_moderate(), return ret;
crypto_pwhash_ALG_ARGON2I13); if (secret_key.size() != crypto_box_SECRETKEYBYTES)
pass.fill(0); return ret;
memset(const_cast<char *>(password.data()), 0, pass.size()); PIByteArray n;
password.fill('\0'); ret.resize(data.size() + crypto_box_MACBYTES);
if (r != 0) return PIByteArray(); n.resize(crypto_box_NONCEBYTES);
return ph; randombytes_buf(n.data(), n.size());
#else if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0)
piCout << "[PICrypt] Error, ALG_ARGON2I13 not availible!"; return PIByteArray();
return PIByteArray(); ret.append(n);
#endif #else
} PICRYPT_DISABLED_WARNING
#endif
return ret;
PIString PICrypt::version() { }
return SODIUM_VERSION_STRING;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) {
PIByteArray ret;
bool PICrypt::init() { #ifdef PIP_CRYPT
static bool inited = false; if (!init()) return ret;
if (inited) return true; if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
// piCout << "[PICrypt]" << "init ..."; if (ok) *ok = false;
inited = sodium_init(); return ret;
if (!inited) inited = sodium_init(); }
// piCout << "[PICrypt]" << "init" << inited; if (secret_key.size() != crypto_box_SECRETKEYBYTES) {
return inited; if (ok) *ok = false;
} return ret;
}
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) {
if (ok) *ok = false;
return ret;
}
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok) *ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray & seed) {
#ifdef crypto_pwhash_ALG_ARGON2I13
// char out[crypto_pwhash_STRBYTES];
PIByteArray pass = password.toUTF8();
PIByteArray n = hash(seed);
PIByteArray ph;
ph.resize(crypto_box_SEEDBYTES);
n.resize(crypto_pwhash_SALTBYTES);
// randombytes_buf(n.data(), n.size());
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data());
int r = crypto_pwhash(ph.data(), ph.size(), (const char*)pass.data(), pass.size(), n.data(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate(), crypto_pwhash_ALG_ARGON2I13);
//crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate());
pass.fill(0);
if (r != 0) return PIByteArray();
return ph;
// PIByteArray ret;
// ret << ph << n << crypto_pwhash_argon2i_opslimit_moderate() << crypto_pwhash_argon2i_memlimit_moderate();
// return ret;
#else
return PIByteArray();
#endif
}
PIString PICrypt::version() {
#ifdef PIP_CRYPT
return SODIUM_VERSION_STRING;
#else
return PIString();
#endif
}
bool PICrypt::init() {
#ifdef PIP_CRYPT
static bool inited = false;
if (inited) return true;
//piCout << "[PICrypt]" << "init ...";
inited = sodium_init();
if (!inited)
inited = sodium_init();
//piCout << "[PICrypt]" << "init" << inited;
return inited;
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}

View File

@@ -1,48 +1,34 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations Class for FFT, IFFT and Hilbert transformations
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pifft.h" #include "pifft.h"
#include "pifft_p.h"
#include "pifft_p.h"
#define _PIFFTW_CPP(type) \
#define _PIFFTW_CPP(type) \ _PIFFTW_P_##type##_::_PIFFTW_P_##type##_() {impl = new PIFFTW_Private<type>();;} \
_PIFFTW_P_##type##_::_PIFFTW_P_##type##_() { \ _PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() {delete (PIFFTW_Private<type>*)impl;} \
impl = new PIFFTW_Private<type>(); \ const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFT(const PIVector<complex<type> > & in) {return ((PIFFTW_Private<type>*)impl)->calcFFT(in);} \
; \ const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFTR(const PIVector<type> & in) {return ((PIFFTW_Private<type>*)impl)->calcFFT(in);} \
} \ const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFTI(const PIVector<complex<type> > & in) {return ((PIFFTW_Private<type>*)impl)->calcFFTinverse(in);} \
_PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() { \ void _PIFFTW_P_##type##_::preparePlan(int size, int op) {return ((PIFFTW_Private<type>*)impl)->preparePlan(size, op);}
delete (PIFFTW_Private<type> *)impl; \
} \ _PIFFTW_CPP(float)
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFT(const PIVector<complex<type>> & in) { \ _PIFFTW_CPP(double)
return ((PIFFTW_Private<type> *)impl)->calcFFT(in); \ _PIFFTW_CPP(ldouble)
} \
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFTR(const PIVector<type> & in) { \
return ((PIFFTW_Private<type> *)impl)->calcFFT(in); \
} \
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFTI(const PIVector<complex<type>> & in) { \
return ((PIFFTW_Private<type> *)impl)->calcFFTinverse(in); \
} \
void _PIFFTW_P_##type##_::preparePlan(int size, int op) { \
return ((PIFFTW_Private<type> *)impl)->preparePlan(size, op); \
}
_PIFFTW_CPP(float)
_PIFFTW_CPP(double)
_PIFFTW_CPP(ldouble)

View File

@@ -1,248 +1,180 @@
/*! \file pifft_p.h /*! \file pifft_p.h
* \brief Class for FFT, IFFT and Hilbert transformations * \brief Class for FFT, IFFT and Hilbert transformations
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Private header for fftw3 Private header for fftw3
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef PIFFT_P_H #ifndef PIFFT_P_H
#define PIFFT_P_H #define PIFFT_P_H
#include "picout.h" #include "pivector.h"
#include "pimathcomplex.h" #include "picout.h"
#include "pivector.h" #if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq) # include "fftw3.h"
# include "fftw3.h" #else
#else # define FFTW_FORWARD 0
# define FFTW_FORWARD 0 # define FFTW_BACKWARD 0
# define FFTW_BACKWARD 0 # define FFTW_ESTIMATE 0
# define FFTW_ESTIMATE 0 # define FFTW_MEASURE 0
# define FFTW_MEASURE 0 #endif
#endif
template <typename T>
template<typename T> class PIFFTW_Private
class PIFFTW_Private { {
public: public:
explicit PIFFTW_Private() { explicit PIFFTW_Private() {
plan = 0; plan = 0;
// #ifndef PIP_FFTW //#ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1"; // piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
// #endif //#endif
p_makeThreadSafe(); p_makeThreadSafe();
} }
~PIFFTW_Private() { p_destroyPlan(plan); } ~PIFFTW_Private() {p_destroyPlan(plan);}
const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) { const PIVector<complex<T> > & calcFFT(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_complex)) { if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size()); p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan"; piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex); prepare = PlanParams(in.size(), fo_complex);
} }
p_executePlan_c2c(plan, in.data(), p_out.data()); p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out; return p_out;
} }
const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) { const PIVector<complex<T> > & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) { if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size()); p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan"; piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real); prepare = PlanParams(in.size(), fo_real);
} }
p_executePlan_r2c(plan, in.data(), p_out.data()); p_executePlan_r2c(plan, in.data(), p_out.data());
return p_out; return p_out;
} }
const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) { const PIVector<complex<T> > & calcFFTinverse(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) { if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size()); p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan"; piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse); prepare = PlanParams(in.size(), fo_inverse);
} }
p_executePlan_c2c(plan, in.data(), p_out.data()); p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out; return p_out;
} }
enum FFT_Operation { enum FFT_Operation {fo_real, fo_complex, fo_inverse};
fo_real,
fo_complex, void preparePlan(int size, int op) {
fo_inverse p_inr.clear();
}; p_in.clear();
p_out.clear();
void preparePlan(int size, int op) { switch ((FFT_Operation)op) {
p_inr.clear(); case fo_real:
p_in.clear(); p_inr.resize(size);
p_out.clear(); p_out.resize(size);
switch ((FFT_Operation)op) { p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED);
case fo_real: break;
p_inr.resize(size); case fo_complex:
p_out.resize(size); p_in.resize(size);
p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED); p_out.resize(size);
break; p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED);
case fo_complex: break;
p_in.resize(size); case fo_inverse:
p_out.resize(size); p_in.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED); p_out.resize(size);
break; p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
case fo_inverse: break;
p_in.resize(size); default:
p_out.resize(size); size = 0;
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED); break;
break; }
default: size = 0; break; prepare = PlanParams(size, (FFT_Operation)op);
} }
prepare = PlanParams(size, (FFT_Operation)op);
} inline void p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {}
inline void p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {}
inline void p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {} inline void p_executePlan(void * plan) {}
inline void p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {} inline void p_executePlan_c2c(void * plan, const void * in, void * out) {}
inline void p_executePlan(void * plan) {} inline void p_executePlan_r2c(void * plan, const void * in, void * out) {}
inline void p_executePlan_c2c(void * plan, const void * in, void * out) {} inline void p_destroyPlan(void *& plan) {}
inline void p_executePlan_r2c(void * plan, const void * in, void * out) {} inline void p_makeThreadSafe() {}
inline void p_destroyPlan(void *& plan) {}
inline void p_makeThreadSafe() {} struct PlanParams {
PlanParams() {size = 0; op = fo_complex;}
struct PlanParams { PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;}
PlanParams() { bool isValid() {return size > 0;}
size = 0; bool operator ==(const PlanParams & v) const {return (v.size == size) && (v.op == op);}
op = fo_complex; bool operator !=(const PlanParams & v) const {return !(*this == v);}
} int size;
PlanParams(int size_, FFT_Operation op_) { FFT_Operation op;
size = size_; };
op = op_;
} PIVector<complex<T> > p_in;
bool isValid() { return size > 0; } PIVector<T> p_inr;
bool operator==(const PlanParams & v) const { return (v.size == size) && (v.op == op); } PIVector<complex<T> > p_out;
bool operator!=(const PlanParams & v) const { return !(*this == v); } void * plan;
int size; PlanParams prepare;
FFT_Operation op; };
};
PIVector<complex<T>> p_in; #ifdef PIP_FFTWf
PIVector<T> p_inr; template<> inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
PIVector<complex<T>> p_out; plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);}
void * plan; template<> inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
PlanParams prepare; plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags);}
}; template<> inline void PIFFTW_Private<float>::p_executePlan(void * plan) {fftwf_execute((fftwf_plan)plan);}
template<> inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out);}
template<> inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);}
#ifdef PIP_FFTWf template<> inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {if (plan) fftwf_destroy_plan((fftwf_plan)plan); plan = 0;}
template<> # ifdef PIP_FFTWf_THREADSAFE
inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { template<> inline void PIFFTW_Private<float>::p_makeThreadSafe() {fftwf_make_planner_thread_safe();}
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags); # endif
} #endif // PIP_FFTWf
template<>
inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { #ifdef PIP_FFTW
plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags); template<> inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
} plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);}
template<> template<> inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
inline void PIFFTW_Private<float>::p_executePlan(void * plan) { plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);}
fftwf_execute((fftwf_plan)plan); template<> inline void PIFFTW_Private<double>::p_executePlan(void * plan) {fftw_execute((fftw_plan)plan);}
} template<> inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);}
template<> template<> inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);}
inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) { template<> inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {if (plan) fftw_destroy_plan((fftw_plan)plan); plan = 0;}
fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out); # ifdef PIP_FFTW_THREADSAFE
} template<> inline void PIFFTW_Private<double>::p_makeThreadSafe() {fftw_make_planner_thread_safe();}
template<> # endif
inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) { #endif // PIP_FFTW
fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);
} #ifdef PIP_FFTWl
template<> template<> inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) { plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);}
if (plan) fftwf_destroy_plan((fftwf_plan)plan); template<> inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = 0; plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);}
} template<> inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {fftwl_execute((fftwl_plan)plan);}
# ifdef PIP_FFTWf_THREADSAFE template<> inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);}
template<> template<> inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);}
inline void PIFFTW_Private<float>::p_makeThreadSafe() { template<> inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {if (plan) fftwl_destroy_plan((fftwl_plan)plan); plan = 0;}
fftwf_make_planner_thread_safe(); # ifdef PIP_FFTWl_THREADSAFE
} template<> inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {fftwl_make_planner_thread_safe();}
# endif # endif
#endif // PIP_FFTWf #endif // PIP_FFTWl
#ifdef PIP_FFTW
template<> #endif // PIFFT_H
inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan(void * plan) {
fftw_execute((fftw_plan)plan);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {
if (plan) fftw_destroy_plan((fftw_plan)plan);
plan = 0;
}
# ifdef PIP_FFTW_THREADSAFE
template<>
inline void PIFFTW_Private<double>::p_makeThreadSafe() {
fftw_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTW
#ifdef PIP_FFTWl
template<>
inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {
fftwl_execute((fftwl_plan)plan);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {
if (plan) fftwl_destroy_plan((fftwl_plan)plan);
plan = 0;
}
# ifdef PIP_FFTWl_THREADSAFE
template<>
inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {
fftwl_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTWl
#endif // PIFFT_H

View File

@@ -1,96 +0,0 @@
#include "curl_thread_pool_p.h"
#include "pihttpclient.h"
#include "pitime.h"
#include <curl/curl.h>
CurlThreadPool::CurlThreadPool() {
curl_global_init(CURL_GLOBAL_DEFAULT);
const int count = 10;
for (int i = 0; i < count; ++i) {
auto * t = new PIThread([this]() { threadFunc(); }, true);
threads << t;
}
}
CurlThreadPool::~CurlThreadPool() {
destroy();
// piCout << "~CurlThreadPool cleanup ...";
curl_global_cleanup();
// piCout << "~CurlThreadPool cleanup ok";
}
void CurlThreadPool::threadFunc() {
if (exiting) return;
// piCout << "threadFuncl w ...";
sem.acquire();
// piCout << "threadFuncl wdone";
if (exiting) return;
PIHTTPClient * c = nullptr;
{
auto cr = clients.getRef();
if (cr->isEmpty()) return;
c = cr->dequeue();
// piCout << "threadFuncl get c";
}
// piCout << "threadFuncl proc c";
procClient(c);
// piCout << "threadFuncl end";
}
void CurlThreadPool::procClient(PIHTTPClient * c) {
{ clients_in_proc.getRef()->append(c); }
if (c->init()) c->perform();
{ clients_in_proc.getRef()->removeOne(c); }
delete c;
}
void CurlThreadPool::registerClient(PIHTTPClient * c) {
clients.getRef()->enqueue(c);
sem.release();
// piCout << "registerClient";
}
CurlThreadPool * CurlThreadPool::instance() {
static CurlThreadPool ret;
return &ret;
}
void CurlThreadPool::destroy() {
// piCout << "~CurlThreadPool";
exiting = true;
for (auto * t: threads)
t->stop();
{
auto cr = clients.getRef();
for (auto c: *cr)
c->abort();
}
{
auto cr = clients_in_proc.getRef();
for (auto c: *cr)
c->abort();
}
// piCout << "~CurlThreadPool release ...";
sem.release(threads.size());
for (auto * t: threads) {
t->waitForFinish();
t->setDebug(false);
t->terminate();
}
// piCout << "~CurlThreadPool delete ...";
piDeleteAllAndClear(threads);
{
auto cr = clients.getRef();
for (auto c: *cr)
delete c;
}
// piCout << "~CurlThreadPool ok";
}

View File

@@ -1,33 +0,0 @@
#ifndef curl_thread_pool_p_H
#define curl_thread_pool_p_H
#include "piprotectedvariable.h"
#include "pisemaphore.h"
#include "pithread.h"
class PIHTTPClient;
class CurlThreadPool {
public:
void registerClient(PIHTTPClient * c);
static CurlThreadPool * instance();
private:
NO_COPY_CLASS(CurlThreadPool)
CurlThreadPool();
~CurlThreadPool();
void destroy();
void threadFunc();
void procClient(PIHTTPClient * c);
PIProtectedVariable<PIQueue<PIHTTPClient *>> clients;
PIProtectedVariable<PIVector<PIHTTPClient *>> clients_in_proc;
PISemaphore sem;
PIVector<PIThread *> threads;
std::atomic_bool exiting = {false};
};
#endif

View File

@@ -1,294 +0,0 @@
#include "pihttpclient.h"
#include "curl_thread_pool_p.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "pisystemtime.h"
#include <curl/curl.h>
#if !defined(CURL_WRITEFUNC_ERROR)
# define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
#endif
int xfer_callback(void * ptr, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int debug_callback(CURL * handle, curl_infotype type, char * data, size_t size, void * ptr) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__debugFunc(type, data, size);
}
PRIVATE_DEFINITION_START(PIHTTPClient)
CURLM * multi = nullptr;
CURL * handle = nullptr;
curl_slist * header_list = nullptr;
bool isInit() const {
return multi && handle;
}
bool init() {
multi = curl_multi_init();
handle = curl_easy_init();
if (!multi || !handle) {
destroy();
return false;
}
return true;
}
void destroy() {
if (multi && handle) curl_multi_remove_handle(multi, handle);
if (header_list) curl_slist_free_all(header_list);
if (handle) curl_easy_cleanup(handle);
if (multi) curl_multi_cleanup(multi);
multi = nullptr;
handle = nullptr;
header_list = nullptr;
}
PRIVATE_DEFINITION_END(PIHTTPClient)
PIHTTPClient::PIHTTPClient() {}
PIHTTPClient::~PIHTTPClient() {}
bool PIHTTPClient::init() {
if (is_cancel) return false;
CurlThreadPool::instance();
if (!PRIVATE->init()) return false;
auto ait = request.arguments().makeIterator();
while (ait.next()) {
if (!url.contains('?'))
url.append('?');
else
url.append('&');
url.append(ait.key().toPercentageEncoding());
url.append('=');
url.append(ait.value().toPercentageEncoding());
}
headers.clear();
auto hit = request.headers().makeIterator();
while (hit.next()) {
headers << hit.key() + ": " + hit.value();
}
for (const auto & h: headers)
PRIVATE->header_list = curl_slist_append(PRIVATE->header_list, h.dataAscii());
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEFUNCTION, writeMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READFUNCTION, readMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFOFUNCTION, xfer_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGFUNCTION, debug_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERFUNCTION, headerFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_URL, url.dataUTF8());
curl_easy_setopt(PRIVATE->handle, CURLOPT_CUSTOMREQUEST, PIHTTP::methodName(request.method()));
curl_easy_setopt(PRIVATE->handle, CURLOPT_HTTPHEADER, PRIVATE->header_list);
curl_easy_setopt(PRIVATE->handle, CURLOPT_NOPROGRESS, 0L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_VERBOSE, 1L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_ERRORBUFFER, buffer_error.data());
curl_easy_setopt(PRIVATE->handle, CURLOPT_SSL_VERIFYPEER, 0L);
if (request.body().isNotEmpty()) {
curl_easy_setopt(PRIVATE->handle, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(PRIVATE->handle, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(request.body().size()));
}
return true;
}
void PIHTTPClient::perform() {
if (!PRIVATE->isInit()) return;
if (!is_cancel) {
// piCout << "perform ...";
PITimeMeasurer tm;
// CURLcode res = curl_easy_perform(PRIVATE->handle);
curl_multi_add_handle(PRIVATE->multi, PRIVATE->handle);
int running_cnt = 1;
do {
CURLMcode mc = curl_multi_perform(PRIVATE->multi, &running_cnt);
// piCout << "curl_multi_perform" << mc << running_cnt;
if (!mc) /* wait for activity, timeout or "nothing" */
mc = curl_multi_poll(PRIVATE->multi, nullptr, 0, 50, nullptr);
if (mc || is_cancel) {
// piCout << "curl_multi_poll() failed";
break;
}
} while (running_cnt > 0 && !is_cancel);
if (is_cancel) {
if (on_abort) on_abort(reply);
PRIVATE->destroy();
return;
}
CURLMsg * m = nullptr;
CURLcode res = (CURLcode)-1;
do {
int msgq = 0;
m = curl_multi_info_read(PRIVATE->multi, &msgq);
if (m && (m->msg == CURLMSG_DONE)) {
res = m->data.result;
if (res == CURLE_OK) {
reply.setBody(std::move(buffer_out));
if (on_finish) on_finish(reply);
} else {
if (res == CURLE_ABORTED_BY_CALLBACK || is_cancel) {
// piCerr << "curl_easy_perform() failed:" << curl_easy_strerror(res);
if (on_abort) on_abort(reply);
} else {
last_error = curl_easy_strerror(res);
if (on_error) on_error(reply);
}
}
break;
}
} while (m && !is_cancel);
if (res == (CURLcode)-1) {
last_error = "CURL error";
if (on_error) on_error(reply);
}
// piCout << "done" << (int)res << "in" << tm.elapsed_m() << ", bytes" << buffer_out.size();
}
// piCout << last_error;
PRIVATE->destroy();
}
void PIHTTPClient::procHeaderLine(PIString & line) {
if (line.startsWith("HTTP"_a)) {
// HTTP/Версия КодСостояния Пояснение
line.cutLeft(5);
line.takeWord();
int code = line.takeWord().toInt();
// piCout << "code" << code;
reply.setCode(static_cast<PIHTTP::Code>(code));
return;
}
int ind = line.find(':');
if (ind < 0) return;
PIString hname = line.takeLeft(ind);
line.cutLeft(1).trim();
reply.addHeader(hname, line);
}
size_t PIHTTPClient::writeMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "writeMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
client->buffer_out.append(contents, bytes);
return bytes;
}
size_t PIHTTPClient::readMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "readMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_READFUNC_ABORT;
const auto & buffer(client->request.body());
if (buffer.isEmpty()) return 0;
// piCout << bytes;
ssize_t ret = piClamp<ssize_t>(bytes, 0, buffer.size_s() - client->read_pos);
if (ret < 0) ret = 0;
if (ret > 0) memcpy(contents, buffer.data(client->read_pos), ret);
return ret;
}
size_t PIHTTPClient::headerFunc(char * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
PIString line = PIString::fromUTF8(contents, bytes).trim();
if (line.isNotEmpty()) client->procHeaderLine(line);
return bytes;
}
int PIHTTPClient::infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
// piCout << "infoFunc" << dltotal << dlnow << ultotal << ulnow;
if (is_cancel) return 1;
return 0;
}
int PIHTTPClient::debugFunc(int type, char * data, size_t size) {
// piCout << "debugFunc" << type << PIString::fromUTF8(data, size);
return 0;
}
PIHTTPClient * PIHTTPClient::create(const PIString & url_, PIHTTP::Method method, const PIHTTP::MessageConst & req) {
PIHTTPClient * ret = new PIHTTPClient();
static_cast<PIHTTP::MessageConst &>(ret->request) = req;
ret->request.setMethod(method);
ret->reply.setMethod(method);
ret->url = url_;
return ret;
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void()> f) {
return onFinish([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void(const PIHTTP::MessageConst &)> f) {
on_finish = f;
return this;
}
PIHTTPClient * PIHTTPClient::onError(std::function<void()> f) {
return onError([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onError(std::function<void(const PIHTTP::MessageConst &)> f) {
on_error = f;
return this;
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void()> f) {
return onAbort([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void(const PIHTTP::MessageConst &)> f) {
on_abort = f;
return this;
}
void PIHTTPClient::start() {
CurlThreadPool::instance()->registerClient(this);
}
void PIHTTPClient::abort() {
is_cancel = true;
if (PRIVATE->isInit()) curl_multi_wakeup(PRIVATE->multi);
}
int PIHTTPClientBase::__infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
return reinterpret_cast<PIHTTPClient *>(this)->infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int PIHTTPClientBase::__debugFunc(int type, char * data, size_t size) {
return reinterpret_cast<PIHTTPClient *>(this)->debugFunc(type, data, size);
}

View File

@@ -1,367 +0,0 @@
#include "microhttpd_server.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include <microhttpd.h>
// clang-format off
#ifdef QNX
# include <arpa/inet.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef BLACKBERRY
# include <netinet/in.h>
# else
# include <sys/dcmd_io-net.h>
# endif
#else
# ifdef WINDOWS
# include <io.h>
# include <winsock2.h>
# include <ws2tcpip.h>
# else
# include <netinet/in.h>
# include <sys/socket.h>
# ifdef LWIP
# include <lwip/sockets.h>
# endif
# endif
#endif
// clang-format on
using namespace PIHTTP;
struct BasicAuthCred {
bool exists = false;
PIString user;
PIString pass;
};
struct MicrohttpdServerConnection {
bool checkBasicAuth();
bool ready();
int sendReply(const MessageMutable & r);
BasicAuthCred getBasicAuthCred();
bool done = false, authorized = false;
Method method = Method::Unknown;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers, args, post;
MHD_Connection * connection = nullptr;
MicrohttpdServer * server = nullptr;
MHD_PostProcessor * postprocessor = nullptr;
};
bool MicrohttpdServerConnection::checkBasicAuth() {
if (headers.contains(Header::Authorization)) {
auto ba_up = getBasicAuthCred();
bool ok = false; // server->callback_auth(ba_up.user, ba_up.pass);
if (server->callback_auth) ok = server->callback_auth(ba_up.user, ba_up.pass);
if (ok) {
authorized = true;
return true;
}
}
// piCout << "miss authorization";
sendReply(MessageMutable::fromCode(Code::Unauthorized)
.addHeader(Header::WWWAuthenticate, "Basic realm=\"%1\", charset=\"UTF-8\""_a.arg(server->realm))
.setBody(PIByteArray::fromAscii("Authorization required")));
// piCout << "answer sent";
return false;
}
bool MicrohttpdServerConnection::ready() {
if (!server) return false;
if (done) return true;
done = true;
MessageMutable rep;
if (method == Method::Get) {
if (path == "/favicon.ico"_a) {
// piCout << "send favicon" << server->favicon.size() << "bytes";
rep.setBody(server->favicon);
sendReply(rep);
return true;
}
}
// piCout << "ready" << (int)method << path << body.size();
MessageMutable req;
req.setMethod(method);
req.setPath(path);
req.setBody(body);
req.headers() = headers;
req.arguments() = args;
rep.setCode(Code::BadRequest);
if (server->callback) rep = server->callback(req);
MicrohttpdServer::addFixedHeaders(rep);
sendReply(rep);
// piCout << "ready ok" << (int)rep.code() << rep.body().size();
return true;
}
int MicrohttpdServerConnection::sendReply(const MessageMutable & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body().size(), (void *)r.body().data(), MHD_RESPMEM_MUST_COPY);
if (!response) {
// piCout << "null response" << r.body.size() << (void *)r.body.data();
return MHD_NO;
}
auto it = r.headers().makeIterator();
while (it.next())
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
// piCout << "status" << r.code;
int ret = MHD_queue_response(connection, static_cast<int>(r.code()), response);
MHD_destroy_response(response);
return ret;
}
BasicAuthCred MicrohttpdServerConnection::getBasicAuthCred() {
BasicAuthCred ret;
char * p = nullptr;
auto u = MHD_basic_auth_get_username_password(connection, &p);
if (u) {
ret.user = PIString::fromUTF8(u);
ret.exists = true;
MHD_free(u);
}
if (p) {
ret.pass = PIString::fromUTF8(p);
ret.exists = true;
MHD_free(p);
}
return ret;
}
void log_callback(void * cls, const char * fmt, va_list ap) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
piCout << "log" << server;
if (!server) return;
char buffer[1_KiB];
piZeroMemory(buffer, 1_KiB);
std::vsnprintf(buffer, 1_KiB, fmt, ap);
piCout << buffer;
}
int iterate_post(void * conn_cls,
MHD_ValueKind kind,
const char * key,
const char * filename,
const char * content_type,
const char * transfer_encoding,
const char * data,
uint64_t off,
size_t size) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)conn_cls;
if (!conn) return MHD_NO;
conn->post[PIString::fromUTF8(key)] = PIString::fromUTF8(data);
return MHD_YES;
}
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
if (!conn) return;
if (conn->postprocessor) {
MHD_destroy_post_processor(conn->postprocessor);
conn->postprocessor = nullptr;
}
conn->ready();
piDeleteSafety(conn);
}
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->headers[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->args[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int answer_callback(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
Method m = Method::Unknown;
if (0 == strcmp(method, "GET"))
m = Method::Get;
else if (0 == strcmp(method, "POST"))
m = Method::Post;
else if (0 == strcmp(method, "HEAD"))
m = Method::Head;
else if (0 == strcmp(method, "PUT"))
m = Method::Put;
else if (0 == strcmp(method, "DELETE"))
m = Method::Delete;
else if (0 == strcmp(method, "CONNECT"))
m = Method::Connect;
else if (0 == strcmp(method, "OPTIONS"))
m = Method::Options;
else if (0 == strcmp(method, "TRACE"))
m = Method::Trace;
else if (0 == strcmp(method, "PATCH"))
m = Method::Patch;
if (m == Method::Unknown) {
piCout << "[MicrohttpdServer]"
<< "Warning:"
<< "Unknown method!";
return MHD_NO;
}
// piCout << "answer" << url << method << (int)m << server;
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
if (!conn) {
conn = new MicrohttpdServerConnection();
conn->connection = connection;
conn->server = server;
conn->path = PIString::fromUTF8(url);
conn->method = m;
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
if (server->isBasicAuthEnabled() && !conn->authorized) {
if (!conn->checkBasicAuth()) return MHD_YES;
}
return MHD_YES;
}
if (m == Method::Unknown) {
return conn->sendReply(MessageMutable::fromCode(Code::MethodNotAllowed));
}
if (*upload_data_size) {
if (!conn->postprocessor) {
conn->postprocessor = MHD_create_post_processor(connection, 64_KiB, (MHD_PostDataIterator)iterate_post, (void *)conn);
}
conn->body.append(upload_data, *upload_data_size);
MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
*upload_data_size = 0;
} else {
// qDebug() << "answer ok";
if (!conn->ready()) return conn->sendReply(MessageMutable::fromCode(Code::InternalServerError));
}
return MHD_YES;
}
PRIVATE_DEFINITION_START(MicrohttpdServer)
MHD_Daemon * daemon;
PRIVATE_DEFINITION_END(MicrohttpdServer)
MicrohttpdServer::MicrohttpdServer() {
PRIVATE->daemon = nullptr;
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
opts[Option::ConnectionTimeout] = 0_s;
realm = "Restricted"_a;
}
MicrohttpdServer::~MicrohttpdServer() {
stop();
}
void MicrohttpdServer::setOption(Option o, PIVariant v) {
opts[o] = std::move(v);
}
void MicrohttpdServer::setFavicon(const PIByteArray & im) {
favicon = im;
}
bool MicrohttpdServer::listen(PINetworkAddress addr) {
stop();
uint flags = 0;
#if MHD_VERSION <= 0x00095100
flags |= MHD_USE_POLL_INTERNALLY;
#else
flags |= MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
#endif
if (opts.value(Option::HTTPSEnabled).toBool()) flags |= MHD_USE_TLS;
mem_key = opts.value(Option::HTTPSMemKey).toByteArray();
if (mem_key.isNotEmpty()) mem_key.append(0);
mem_cert = opts.value(Option::HTTPSMemCert).toByteArray();
if (mem_cert.isNotEmpty()) mem_cert.append(0);
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
if (key_pass.isNotEmpty()) key_pass.append(0);
sockaddr_in sa_addr;
piZeroMemory(sa_addr);
sa_addr.sin_port = htons(addr.port());
sa_addr.sin_addr.s_addr = addr.ip();
sa_addr.sin_family = AF_INET;
PIVector<MHD_OptionItem> options;
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
if (opts.value(Option::HTTPSEnabled).toBool()) {
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
}
options.append({MHD_OPTION_END, 0, nullptr});
PRIVATE->daemon = MHD_start_daemon(flags,
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_callback,
this,
MHD_OPTION_ARRAY,
options.data(),
MHD_OPTION_END);
return isListen();
}
bool MicrohttpdServer::isListen() const {
return PRIVATE->daemon;
}
void MicrohttpdServer::stop() {
if (PRIVATE->daemon) {
MHD_stop_daemon(PRIVATE->daemon);
PRIVATE->daemon = nullptr;
}
}
void MicrohttpdServer::addFixedHeaders(MessageMutable & msg) {
if (!msg.headers().contains(Header::ContentType)) {
if (msg.body().isNotEmpty()) {
if (msg.body().startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
msg.addHeader(Header::ContentType, "text/html; charset=utf-8");
else if (msg.body()[0] == '[' || msg.body()[0] == '{')
msg.addHeader(Header::ContentType, "application/json; charset=utf-8");
}
}
msg.addHeader(Header::AccessControlAllowOrigin, "*");
}

View File

@@ -1,90 +0,0 @@
#include "pihttpserver.h"
#include "piliterals_string.h"
PIHTTPServer::PIHTTPServer() {
setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable {
PIHTTP::MessageMutable reply;
reply.setCode(PIHTTP::Code::NotFound);
auto in_path = r.path().split("/");
in_path.removeAll("");
auto it = functions.makeReverseIterator();
bool found = false;
while (it.next()) {
if (it.value().function) {
if (it.value().method == r.method()) {
if (it.value().match(in_path)) {
reply = it.value().function(r);
found = true;
break;
}
}
}
}
if (!found && unhandled) reply = unhandled(r);
auto hit = reply_headers.makeIterator();
while (hit.next())
reply.addHeader(hit.key(), hit.value());
return reply;
});
}
PIHTTPServer::~PIHTTPServer() {
stop();
}
void PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor) {
auto & ep(functions[path + PIString::fromNumber(static_cast<int>(method))]);
ep.path = path.split("/");
ep.method = method;
ep.function = functor;
ep.path.removeAll("");
}
void PIHTTPServer::registerUnhandled(RequestFunction functor) {
unhandled = functor;
}
void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) {
auto pl = path.split("/");
pl.removeAll("");
auto it = functions.makeIterator();
while (it.next()) {
if (it.value().method == method) {
if (it.value().path == pl) {
functions.remove(it.key());
break;
}
}
}
}
void PIHTTPServer::unregisterPath(const PIString & path) {
auto pl = path.split("/");
pl.removeAll("");
auto it = functions.makeIterator();
PIStringList keys;
while (it.next()) {
if (it.value().path == pl) {
keys << it.key();
}
}
for (const auto & k: keys)
functions.remove(k);
}
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
if (in_path.size() != path.size()) return false;
for (int i = 0; i < path.size_s(); ++i) {
if (path[i] == "*"_a) continue;
if (path[i] != in_path[i]) return false;
}
return true;
}

View File

@@ -1,270 +1,266 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Broadcast for all interfaces, including loopback Broadcast for all interfaces, including loopback
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pibroadcast.h" #include "pibroadcast.h"
#include "piliterals_time.h" /** \class PIBroadcast
* \brief Broadcast for all interfaces, including loopback
/** \class PIBroadcast *
* \brief Broadcast for all interfaces, including loopback * \section PIBroadcast_synopsis Synopsis
* * %PIBroadcast used as multichannel IO device. It can use
* \section PIBroadcast_synopsis Synopsis * multicast, broadcast and loopback ethernet channels to
* %PIBroadcast used as multichannel IO device. It can use * send/receive packets. \a send() function send packet to
* multicast, broadcast and loopback ethernet channels to * all initialized ethernets. \a receiveEvent() raised on
* send/receive packets. \a send() function send packet to * packet received by any ethernet. All multi/broadcast
* all initialized ethernets. \a receiveEvent() raised on * ethernets created for all current addresses, obtained
* packet received by any ethernet. All multi/broadcast * by \a PIEthernets::allAddresses().
* ethernets created for all current addresses, obtained *
* by \a PIEthernets::allAddresses(). * * \a Multicast ethernets use \a multicastGroup() and \a multicastPort()
* * * \a Broadcast ethernets use \a broadcastPort()
* * \a Multicast ethernets use \a multicastGroup() and \a multicastPort() * * \a Loopback ethernet use \a loopbackPortsCount() started from \a loopbackPort()
* * \a Broadcast ethernets use \a broadcastPort() *
* * \a Loopback ethernet use \a loopbackPortsCount() started from \a loopbackPort() * %PIBroadcast starts thread, which every 3 seconds check if
* * current \a PIEthernet::allAddresses() was changed and call
* %PIBroadcast starts thread, which every 3 seconds check if * \a reinit() if it necessary.
* current \a PIEthernet::allAddresses() was changed and call *
* \a reinit() if it necessary. */
*
*/ #define MULTICAST_TTL 4
#define MULTICAST_TTL 4
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
_channels = All;
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() { eth_lo = 0;
_channels = All; mcast_address.set("232.13.3.14", 14100);
eth_lo = 0; lo_port = 14200;
mcast_address.set("232.13.3.14", 14100); lo_pcnt = 5;
lo_port = 14200; _started = false;
lo_pcnt = 5; _send_only = send_only;
_started = false; _reinit = true;
_send_only = send_only; }
_reinit = true;
}
PIBroadcast::~PIBroadcast() {
PIThread::stop();
PIBroadcast::~PIBroadcast() { mcast_mutex.unlock();
PIThread::stopAndWait(); destroyAll();
// mcast_mutex.unlock(); }
destroyAll();
}
void PIBroadcast::setChannels(PIBroadcast::Channels ch) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setChannels(PIBroadcast::Channels ch) { _channels = ch;
PIMutexLocker ml(mcast_mutex); _reinit = true;
_channels = ch; }
_reinit = true;
}
void PIBroadcast::setMulticastGroup(const PIString & mg) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setMulticastGroup(const PIString & mg) { mcast_address.setIP(mg);
PIMutexLocker ml(mcast_mutex); _reinit = true;
mcast_address.setIP(mg); }
_reinit = true;
}
void PIBroadcast::setMulticastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setMulticastPort(ushort port) { mcast_address.setPort(port);
PIMutexLocker ml(mcast_mutex); _reinit = true;
mcast_address.setPort(port); }
_reinit = true;
}
void PIBroadcast::setMulticastAddress(const PIEthernet::Address & addr) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setMulticastAddress(const PINetworkAddress & addr) { mcast_address = addr;
PIMutexLocker ml(mcast_mutex); _reinit = true;
mcast_address = addr; }
_reinit = true;
}
void PIBroadcast::setBroadcastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setBroadcastPort(ushort port) { bcast_port = port;
PIMutexLocker ml(mcast_mutex); _reinit = true;
bcast_port = port; }
_reinit = true;
}
void PIBroadcast::setLoopbackPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setLoopbackPort(ushort port) { lo_port = port;
PIMutexLocker ml(mcast_mutex); _reinit = true;
lo_port = port; }
_reinit = true;
}
void PIBroadcast::setLoopbackPortsCount(int count) {
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::setLoopbackPortsCount(int count) { lo_pcnt = count;
PIMutexLocker ml(mcast_mutex); _reinit = true;
lo_pcnt = count; }
_reinit = true;
}
void PIBroadcast::destroyAll() {
piForeach (PIEthernet * e, eth_mcast) {
void PIBroadcast::destroyAll() { e->stopThreadedRead();
for (auto * e: eth_mcast) { delete e;
e->stopAndWait(); }
piDeleteSafety(e); eth_mcast.clear();
} if (eth_lo) {
eth_mcast.clear(); eth_lo->stopThreadedRead();
if (eth_lo) { delete eth_lo;
eth_lo->stopAndWait(); eth_lo = 0;
piDeleteSafety(eth_lo); }
} }
}
void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
void PIBroadcast::initAll(PIVector<PINetworkAddress> al) { PIMutexLocker ml(mcast_mutex);
PIMutexLocker ml(mcast_mutex); destroyAll();
destroyAll(); _reinit = false;
_reinit = false; prev_al = al;
prev_al = al; al.removeAll(PIEthernet::Address("127.0.0.1"));
al.removeAll(PINetworkAddress("127.0.0.1")); al << mcast_address;
al << mcast_address; eth_mcast.clear();
eth_mcast.clear(); PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces(); piForeachC (PIEthernet::Address & a, al) {
for (const auto & a: al) { PIEthernet * ce = 0;
PIEthernet * ce = 0; //piCout << "mcast try" << a;
// piCout << "mcast try" << a; if (_channels[Multicast]) {
if (_channels[Multicast]) { ce = new PIEthernet();
ce = new PIEthernet(); ce->setDebug(false);
ce->setDebug(false); ce->setName("PIMulticast_" + a.toString());
ce->setName("PIMulticast_" + a.toString()); ce->setParameters(0);
ce->setParameters(0); ce->setSendAddress(mcast_address);
ce->setSendAddress(mcast_address); ce->setMulticastTTL(MULTICAST_TTL);
ce->setMulticastTTL(MULTICAST_TTL); if (!_send_only) {
if (!_send_only) { ce->setReadAddress(a.ipString(), mcast_address.port());
ce->setReadAddress(a.ipString(), mcast_address.port()); ce->joinMulticastGroup(mcast_address.ipString());
ce->joinMulticastGroup(mcast_address.ipString()); //piCout << "mcast " << ce->readAddress() << ce->sendAddress();
// piCout << "mcast " << ce->readAddress() << ce->sendAddress(); if (ce->open()) {
if (ce->open()) { eth_mcast << ce;
eth_mcast << ce; CONNECTU(ce, threadedReadEvent, this, mcastRead);
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead); } else {
} else { delete ce;
delete ce; }
} } else {
} else { eth_mcast << ce;
eth_mcast << ce; }
} }
}
if (_channels[Broadcast]) {
if (_channels[Broadcast]) { ce = new PIEthernet();
ce = new PIEthernet(); ce->setDebug(false);
ce->setDebug(false); ce->setName("PIMulticast_" + a.toString());
ce->setName("PIMulticast_" + a.toString()); ce->setParameters(PIEthernet::Broadcast);
ce->setParameters(PIEthernet::Broadcast); const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString()); PIEthernet::Address nm((cint == 0) ? "255.255.255.0" : cint->netmask);
PINetworkAddress nm((cint == 0) ? "255.255.255.0" : cint->netmask); ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port); if (!_send_only) {
if (!_send_only) { ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port));
ce->setReadAddress(PINetworkAddress(a.ip(), bcast_port)); //piCout << "bcast " << ce->readAddress() << ce->sendAddress();
// piCout << "bcast " << ce->readAddress() << ce->sendAddress(); if (ce->open()) {
if (ce->open()) { eth_mcast << ce;
eth_mcast << ce; CONNECTU(ce, threadedReadEvent, this, mcastRead);
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead); } else {
} else { delete ce;
delete ce; }
} } else {
} else { eth_mcast << ce;
eth_mcast << ce; }
} }
} }
}
if (_channels[Loopback]) {
if (_channels[Loopback]) { eth_lo = new PIEthernet();
eth_lo = new PIEthernet(); eth_lo->setDebug(false);
eth_lo->setDebug(false); eth_lo->setName("PIMulticast_loopback");
eth_lo->setName("PIMulticast_loopback"); if (!_send_only) {
if (!_send_only) { eth_lo->setParameter(PIEthernet::ReuseAddress, false);
eth_lo->setParameter(PIEthernet::ReuseAddress, false); CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
CONNECT2(void, const uchar *, ssize_t, eth_lo, threadedReadEvent, this, mcastRead); for (int i = 0; i < lo_pcnt; ++i) {
for (int i = 0; i < lo_pcnt; ++i) { eth_lo->setReadAddress("127.0.0.1", lo_port + i);
eth_lo->setReadAddress("127.0.0.1", lo_port + i); if (eth_lo->open()) {
if (eth_lo->open()) { //piCout << "bind local to" << (lo_port + i);
// piCout << "bind local to" << (lo_port + i); break;
break; }
} }
} }
} }
} }
}
void PIBroadcast::send(const PIByteArray & data) {
void PIBroadcast::send(const PIByteArray & data) { if (!isRunning()) {
/*if (!isRunning()) { reinit();
reinit(); PIThread::start(3000);
PIThread::start(3000); }
}*/ PIByteArray cd = cryptData(data);
PIByteArray cd = cryptData(data); if (cd.isEmpty()) return;
if (cd.isEmpty()) return; PIMutexLocker ml(mcast_mutex);
PIMutexLocker ml(mcast_mutex); piForeach (PIEthernet * e, eth_mcast) e->send(cd);
for (auto * e: eth_mcast) if (eth_lo) {
e->send(cd); for (int i = 0; i < lo_pcnt; ++i) {
if (eth_lo) { eth_lo->send("127.0.0.1", lo_port + i, cd);
for (int i = 0; i < lo_pcnt; ++i) { }
eth_lo->send("127.0.0.1", lo_port + i, cd); }
} }
}
}
void PIBroadcast::startRead() {
if (!isRunning()) {
void PIBroadcast::startRead() { _started = false;
if (!isRunning()) { reinit();
_started = false; PIThread::start(3000);
reinit(); }
PIThread::start(3_s); if (_send_only) return;
} PIMutexLocker ml(mcast_mutex);
if (_send_only) return; piForeach (PIEthernet * e, eth_mcast) e->startThreadedRead();
PIMutexLocker ml(mcast_mutex); if (eth_lo) eth_lo->startThreadedRead();
for (auto * e: eth_mcast) _started = true;
e->startThreadedRead(); }
if (eth_lo) eth_lo->startThreadedRead();
_started = true;
} void PIBroadcast::stopRead() {
if (isRunning()) stop();
PIMutexLocker ml(mcast_mutex);
void PIBroadcast::stopRead() { piForeach (PIEthernet * e, eth_mcast) e->stopThreadedRead();
if (isRunning()) stopAndWait(); if (eth_lo) eth_lo->stopThreadedRead();
PIMutexLocker ml(mcast_mutex); _started = false;
for (auto * e: eth_mcast) }
e->stopAndWait(5_s);
if (eth_lo) eth_lo->stopAndWait(5_s);
_started = false; void PIBroadcast::reinit() {
} initAll(PIEthernet::allAddresses());
if (_started) startRead();
}
void PIBroadcast::reinit() {
initAll(PIEthernet::allAddresses());
if (_started) startRead(); void PIBroadcast::mcastRead(uchar * data, int size) {
} PIByteArray cd = decryptData(PIByteArray(data, size));
if (cd.isEmpty()) return;
received(cd);
void PIBroadcast::mcastRead(const uchar * data, ssize_t size) { receiveEvent(cd);
PIByteArray cd = decryptData(PIByteArray(data, size)); }
if (cd.isEmpty()) return;
received(cd);
receiveEvent(cd); void PIBroadcast::run() {
} PIVector<PIEthernet::Address> al = PIEthernet::allAddresses();
mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al);
void PIBroadcast::run() { mcast_mutex.unlock();
PIVector<PINetworkAddress> al = PIEthernet::allAddresses(); if (ac || r) reinit();
mcast_mutex.lock(); if (ac) addressesChanged();
bool r = _reinit, ac = (al != prev_al); }
mcast_mutex.unlock();
if (ac || r) reinit();
if (ac) addressesChanged();
}

View File

@@ -1,131 +1,121 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Base class for ethernet utils Base class for ethernet utils
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piethutilbase.h" #include "piethutilbase.h"
#ifdef PIP_CRYPT
#include "pitranslator.h" # include "picrypt.h"
#ifdef PIP_CRYPT #endif
# include "picrypt.h"
#endif /** \class PIEthUtilBase
* \brief Base class for ethernet utils
/** \class PIEthUtilBase *
* \brief Base class for ethernet utils * \section PIEthUtilBase_synopsis Synopsis
* * %PIEthUtilBase provides crypt layer for derived classes:
* \section PIEthUtilBase_synopsis Synopsis * \a PIStreamPacker and \a PIBroadcast. All input and output
* %PIEthUtilBase provides crypt layer for derived classes: * (sended and received) data can be decrypted/encrypted by this layer.
* \a PIStreamPacker and \a PIBroadcast. All input and output *
* (sended and received) data can be decrypted/encrypted by this layer. * By default crypt layer is disabled.
* *
* By default crypt layer is disabled. * You can separetely enable it and set ready-to-use
* * key by \a setCryptEnabled() and \a setCryptKey(). Or you can
* You can separetely enable it and set ready-to-use * use \a createCryptKey() to generate key from your passphrase
* key by \a setCryptEnabled() and \a setCryptKey(). Or you can * and automatic enable crypt layer.
* use \a createCryptKey() to generate key from your passphrase *
* and automatic enable crypt layer. * \note To use crypt layer, PIP should be built with crypt module,
* * otherwise your in/out data will be lost.
* \note To use crypt layer, PIP should be built with crypt module, *
* otherwise your in/out data will be lost. * You can use this class as base for your own classes. Use \a cryptData()
* * and \a decryptData() when send and receive your data.
* You can use this class as base for your own classes. Use \a cryptData() *
* and \a decryptData() when send and receive your data. */
*
*/
PIEthUtilBase::PIEthUtilBase() {
_crypt = false;
PIEthUtilBase::PIEthUtilBase() { }
_crypt = false;
}
PIEthUtilBase::~PIEthUtilBase() {
}
PIEthUtilBase::~PIEthUtilBase() {}
void PIEthUtilBase::setCryptEnabled(bool on) {
void PIEthUtilBase::setCryptEnabled(bool on) { _crypt = on;
_crypt = on; }
}
void PIEthUtilBase::cryptEnable() {
void PIEthUtilBase::cryptEnable() { setCryptEnabled(true);
setCryptEnabled(true); }
}
void PIEthUtilBase::cryptDisable() {
void PIEthUtilBase::cryptDisable() { setCryptEnabled(false);
setCryptEnabled(false); }
}
bool PIEthUtilBase::isCryptEnabled() const {
bool PIEthUtilBase::isCryptEnabled() const { return _crypt;
return _crypt; }
}
void PIEthUtilBase::setCryptKey(const PIByteArray & k) {
void PIEthUtilBase::setCryptKey(const PIByteArray & k) { _key = k;
_key = k; setCryptEnabled(true);
setCryptEnabled(true); }
}
void PIEthUtilBase::createCryptKey(const PIString & k) {
void PIEthUtilBase::createCryptKey(const PIString & k) { #ifdef PIP_CRYPT
#ifdef PIP_CRYPT _key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash("sodium_bug"); _key = PICrypt::hash(k);
_key = PICrypt::hash(k); #else
#else piCout << "[PIEthUtilBase] PICrypt wasn`t built!";
piCout << "[PIEthUtilBase]" #endif
<< "PICrypt wasn`t built!"_tr("PIEthUtilBase"); _crypt = true;
#endif }
_crypt = true;
}
PIByteArray PIEthUtilBase::cryptKey() const {
return _key;
PIByteArray PIEthUtilBase::cryptKey() const { }
return _key;
}
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) {
if (!_crypt) return data;
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) { return
if (!_crypt) return data; #ifdef PIP_CRYPT
return PICrypt::crypt(data, _key);
#ifdef PIP_CRYPT #else
PICrypt::crypt(data, _key); PIByteArray();
#else #endif
PIByteArray(); }
#endif
}
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
if (!_crypt) return data;
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) { #ifdef PIP_CRYPT
if (!_crypt) return data; bool ok = false;
#ifdef PIP_CRYPT PIByteArray ret = PICrypt::decrypt(data, _key, &ok);
bool ok = false; if (!ok) return PIByteArray();
PIByteArray ret = PICrypt::decrypt(data, _key, &ok); return ret;
if (!ok) return PIByteArray(); #else
return ret; return PIByteArray();
#else #endif
return PIByteArray(); }
#endif
}
size_t PIEthUtilBase::cryptSizeAddition() {
#ifdef PIP_CRYPT
return PICrypt::sizeCrypt();
#else
return 0;
#endif
}

View File

@@ -1,199 +0,0 @@
/*
PIP - Platform Independent Primitives
PIPackedTCP
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pipackedtcp.h"
#include "piethernet.h"
#include "piliterals.h"
/** \class PIPackedTCP pipackedtcp.h
* \brief
* TCP packed channel
*
* \details
* \section PITCP_sec0 Synopsis
* %PIEthernet designed to work with IPv4 network via two protocols:
* UDP and TCP. This class allow you send and receive packets to/from
* another computer through network. Also it supports broadcast and
* multicast extensions.
*
* */
PIPackedTCP::PIPackedTCP(Role role, const PINetworkAddress & addr): m_role(role) {
setMode(PIIODevice::ReadWrite);
packer.setCryptEnabled(false);
CONNECTL(&packer, packetReceiveEvent, [this](PIByteArray & data) {
PIMutexLocker ml(rec_mutex);
rec_queue.enqueue(data);
});
init();
setAddress(addr);
}
PIPackedTCP::~PIPackedTCP() {
stopAndWait();
if (client) client->stopAndWait();
if (eth) eth->stopAndWait();
piDeleteSafety(eth);
}
void PIPackedTCP::setAddress(const PINetworkAddress & addr) {
m_addr = addr;
setPath(m_addr.toString());
}
bool PIPackedTCP::isConnected() const {
if (m_role == Client) {
return eth->isConnected();
} else {
if (client) return client->isConnected();
}
return false;
}
bool PIPackedTCP::isConnecting() const {
if (m_role == Client) {
return eth->isConnecting();
} else {
if (client) return client->isConnecting();
}
return false;
}
void PIPackedTCP::init() {
if (client) client->stopAndWait();
if (eth) eth->stopAndWait();
piDeleteSafety(eth);
eth = new PIEthernet(m_role == Client ? PIEthernet::TCP_Client : PIEthernet::TCP_Server);
if (m_role == Client) {
eth->setReopenTimeout(100_ms);
packer.assignDevice(eth);
CONNECTL(eth, connected, [this]() {
packer.clear();
connected();
});
CONNECTL(eth, disconnected, [this](bool) {
packer.clear();
eth->connect(path(), true);
disconnected();
});
} else {
CONNECTL(eth, newConnection, [this](PIEthernet * c) {
if (client) client->stopAndWait();
piDeleteSafety(client);
client = c;
// piCout << "Server connected" << client;
packer.assignDevice(client);
CONNECTL(client, disconnected, [this](bool) {
// packer.assignDevice(nullptr); WTF?
packer.clear();
disconnected();
});
client->startThreadedRead();
connected();
});
}
}
PIIODevice::DeviceInfoFlags PIPackedTCP::deviceInfoFlags() const {
return PIIODevice::Reliable;
}
PIString PIPackedTCP::constructFullPathDevice() const {
return PIString(m_role == Client ? "client" : "server") + ":" + path();
}
void PIPackedTCP::configureFromFullPathDevice(const PIString & full_path) {
PIStringList pl = full_path.split(":");
if (pl.size() >= 1) {
PIString p = pl[0].toLowerCase().left(1);
if (p == "c") m_role = Client;
if (p == "s") m_role = Server;
init();
}
PINetworkAddress addr("0.0.0.0", 13362);
if (pl.size() >= 2) {
if (pl[1].isNotEmpty()) addr.setIP(pl[1]);
}
if (pl.size() >= 3) {
if (pl[2].isNotEmpty()) addr.setPort(pl[2].toInt());
}
setAddress(addr);
}
ssize_t PIPackedTCP::readDevice(void * read_to, ssize_t max_size) {
PIMutexLocker ml(rec_mutex);
if (rec_queue.isNotEmpty()) {
auto d = rec_queue.dequeue();
auto sz = piMin(max_size, d.size_s());
if (read_to) memcpy(read_to, d.data(), sz);
return sz;
}
return 0;
}
ssize_t PIPackedTCP::writeDevice(const void * data, ssize_t max_size) {
if (!isConnected()) return 0;
packer.send(PIByteArray(data, max_size));
// piCout << m_role << "write" << eth;
return max_size;
/*if (m_role == Client) {
return eth->write(data, max_size);
} else {
if (client) return client->write(data, max_size);
}*/
}
bool PIPackedTCP::openDevice() {
if (m_role == Client) {
if (eth->isConnected()) return true;
if (eth->isConnecting()) return false;
packer.clear();
bool ret = eth->connect(path(), false);
eth->startThreadedRead();
return ret;
} else {
return eth->listen(path(), false);
}
return false;
}
bool PIPackedTCP::closeDevice() {
if (client) {
client->close();
client->stopAndWait();
piDeleteSafety(client);
// packer.assignDevice(nullptr); WTF?
}
return eth->close();
}

View File

@@ -1,176 +1,202 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Simple packet wrap aroud any PIIODevice Simple packet wrap aroud any PIIODevice
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic push # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnonnull" # pragma GCC diagnostic ignored "-Wnonnull"
#endif #endif
#include "pistreampacker.h" #include "pistreampacker.h"
#include "piiodevice.h"
#include "piiodevice.h" #ifdef __GNUC__
#include "pitranslator.h" # pragma GCC diagnostic pop
#ifdef __GNUC__ #endif
# pragma GCC diagnostic pop
#endif /** \class PIStreamPacker
* \brief Simple packet wrap aroud any PIIODevice
/** \class PIStreamPacker *
* \brief Simple packet wrap aroud any PIIODevice * \section PIStreamPacker_synopsis Synopsis
* * %PIStreamPacker provides simple pack/unpack logic for any data packets.
* \section PIStreamPacker_synopsis Synopsis *
* %PIStreamPacker provides simple pack/unpack logic for any data packets. * When you call \a send() function data splited into several
* * parts, \a packetSign() prepended to first part and \a sendRequest()
* When you call \a send() function data splited into several * event raised several times.
* parts, \a packetSign() prepended to first part and \a sendRequest() *
* event raised several times. * When your device receive some data, call \a received() function.
* * \a packetReceiveEvent() event will be raised when packet will be
* When your device receive some data, call \a received() function. * collected.
* \a packetReceiveEvent() event will be raised when packet will be *
* collected. * Use \a assignDevice() to connect device to this %PIStreamPacker.
* *
* Use \a assignDevice() to connect device to this %PIStreamPacker. */
*
*/
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
crypt_frag = crypt_size = false;
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() { aggressive_optimization = true;
packet_size = -1; packet_size = -1;
if (dev) assignDevice(dev); size_crypted_size = sizeof(int);
} crypt_frag_size = 1024*1024;
max_packet_size = 1400;
void PIStreamPacker::clear() { packet_sign = 0xAFBE;
packet.clear(); assignDevice(dev);
packet_size = -1; }
stream.clear();
}
void PIStreamPacker::setCryptSizeEnabled(bool on) {
crypt_size = on;
void PIStreamPacker::send(const PIByteArray & data) { if (crypt_size) {
if (data.isEmpty()) return; PIByteArray ba; ba << int(0);
PIByteArray cd = cryptData(data); size_crypted_size = cryptData(ba).size_s();
// piCout << "crypt" << data.size() << "->" << cd.size() << key().size(); } else
PIByteArray hdr, part; size_crypted_size = sizeof(int);
hdr << packet_sign; }
if (crypt_size) {
PIByteArray crsz;
crsz << int(cd.size_s()); void PIStreamPacker::clear() {
hdr.append(cryptData(crsz)); packet.clear();
} else packet_size = -1;
hdr << int(cd.size_s()); stream.clear();
cd.insert(0, hdr); }
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) void PIStreamPacker::send(const PIByteArray & data) {
part = PIByteArray(cd.data(pst), cd.size_s() - pst); if (data.isEmpty()) return;
else PIByteArray cd;
part = PIByteArray(cd.data(pst), max_packet_size); if (crypt_frag) {
// piCout << "send" << part.size(); int fcnt = (data.size_s() - 1) / crypt_frag_size + 1, fst = 0;
sendRequest(part); //piCout << "crypt_frag send" << fcnt << "frags";
pst += max_packet_size; PIByteArray frag;
} for (int i = 0; i < fcnt; ++i) {
} if (i == fcnt - 1) frag = PIByteArray(data.data(fst), data.size_s() - fst);
else frag = PIByteArray(data.data(fst), crypt_frag_size);
fst += crypt_frag_size;
void PIStreamPacker::received(const uchar * readed, ssize_t size) { cd << cryptData(frag);
if (size <= 0) return; }
received(PIByteArray(readed, size)); } else {
} cd = cryptData(data);
}
//piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
void PIStreamPacker::received(const PIByteArray & data) { PIByteArray hdr, part;
stream.append(data); hdr << packet_sign;
// piCout << "rec" << data.size(); if (crypt_size) {
while (!stream.isEmpty()) { PIByteArray crsz; crsz << int(cd.size_s());
int hdr_size = sizeof(packet_sign) + sizeCryptedSize(); hdr.append(cryptData(crsz));
if (packet_size < 0) { } else
if (stream.size_s() < hdr_size) return; hdr << int(cd.size_s());
ushort sign(0); cd.insert(0, hdr);
memcpy(&sign, stream.data(), 2); int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
if (sign != packet_sign) { for (int i = 0; i < pcnt; ++i) {
if (aggressive_optimization) if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
stream.clear(); else part = PIByteArray(cd.data(pst), max_packet_size);
else //piCout << "send" << part.size();
stream.pop_front(); sendRequest(part);
continue; pst += max_packet_size;
} }
int sz = -1; }
if (crypt_size) {
PIByteArray crsz(sizeCryptedSize());
memcpy(crsz.data(), stream.data(2), crsz.size()); void PIStreamPacker::received(uchar * readed, int size) {
crsz = decryptData(crsz); received(PIByteArray(readed, size));
if (crsz.size() < sizeof(sz)) { }
if (aggressive_optimization)
stream.clear();
else void PIStreamPacker::received(const PIByteArray & data) {
stream.pop_front(); stream.append(data);
continue; //piCout << "rec" << data.size();
} while (!stream.isEmpty()) {
crsz >> sz; int hdr_size = sizeof(packet_sign) + size_crypted_size;
} else { if (packet_size < 0) {
memcpy(&sz, stream.data(2), sizeCryptedSize()); if (stream.size_s() < hdr_size) return;
} ushort sign(0);
if (sz < 0) { memcpy(&sign, stream.data(), 2);
if (aggressive_optimization) if (sign != packet_sign) {
stream.clear(); if (aggressive_optimization) stream.clear();
else else stream.pop_front();
stream.pop_front(); continue;
continue; }
} int sz = -1;
stream.remove(0, hdr_size); if (crypt_size) {
packet.clear(); PIByteArray crsz((uint)size_crypted_size);
packet_size = sz; memcpy(crsz.data(), stream.data(2), size_crypted_size);
if (packet_size == 0) crsz = decryptData(crsz);
packet_size = -1; if (crsz.size() < sizeof(sz)) {
else if (aggressive_optimization) stream.clear();
startPacketReceive(packet_size); else stream.pop_front();
continue; continue;
} else { }
int ps = piMini(stream.size_s(), packet_size - packet.size_s()); crsz >> sz;
packet.append(stream.data(), ps); } else {
stream.remove(0, ps); memcpy(&sz, stream.data(2), size_crypted_size);
if (packet.size_s() == packet_size) { }
PIByteArray cd = decryptData(packet); if (sz < 0) {
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size(); if (aggressive_optimization) stream.clear();
if (!cd.isEmpty()) { else stream.pop_front();
endPacketReceive(); continue;
packetReceived(cd); }
packetReceiveEvent(cd); stream.remove(0, hdr_size);
} packet.clear();
packet.clear(); packet_size = sz;
packet_size = -1; if (packet_size == 0)
} packet_size = -1;
} continue;
} } else {
} int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps);
stream.remove(0, ps);
void PIStreamPacker::assignDevice(PIIODevice * dev) { if (packet.size_s() == packet_size) {
if (!dev) { PIByteArray cd;
piCoutObj << "Error! device is NULL"; if (crypt_frag) {
return; //piCout << "decrypt frags ..." << packet_size;
} while (packet.size_s() >= 4) {
if (!dev->infoFlags()[PIIODevice::Reliable]) { //piCout << "decrypt frags take data ...";
piCoutObj << "Warning! Not recommended to use with non-reliable device"_tr("PIStreamPacker") << dev; PIByteArray frag;
} //piCout << "decrypt frags take data done" << frag.size_s();
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received); packet >> frag;
CONNECT1(void, PIByteArray, this, sendRequest, dev, write); if (frag.isEmpty()) {
} //piCout << "decrypt frags corrupt, break";
cd.clear();
uint PIStreamPacker::sizeCryptedSize() { break;
return sizeof(int) + (crypt_size ? cryptSizeAddition() : 0); }
} cd.append(decryptData(frag));
//piCout << "decrypt frags add" << frag.size_s();
}
//piCout << "decrypt frags done" << cd.size();
} else {
cd = decryptData(packet);
}
//piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
if (!cd.isEmpty()) {
packetReceived(cd);
packetReceiveEvent(cd);
}
packet.clear();
packet_size = -1;
}
}
}
}
void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) return;
if (!dev->infoFlags()[PIIODevice::Reliable])
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
CONNECTU(dev, threadedReadEvent, this, received);
CONNECTU(this, sendRequest, dev, write);
}

View File

@@ -1,20 +1,20 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PILuaProgram PILuaProgram
Andrey Bychkov work.a.b@yandex.ru Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piluaprogram.h" #include "piluaprogram.h"
@@ -50,3 +50,4 @@ luabridge::LuaRef PILuaProgram::getGlobal(const PIString & name) {
luabridge::Namespace PILuaProgram::getGlobalNamespace() { luabridge::Namespace PILuaProgram::getGlobalNamespace() {
return luabridge::getGlobalNamespace(PRIVATE->lua_state); return luabridge::getGlobalNamespace(PRIVATE->lua_state);
} }

Some files were not shown because too many files have changed in this diff Show More