commit b340c7c59486acc3173a0591f36918f33261a0f9 Author: 歪脖子 Date: Thu Oct 26 09:46:24 2023 +0800 Initial Commit diff --git a/JCPrinterSDK.xcodeproj/project.pbxproj b/JCPrinterSDK.xcodeproj/project.pbxproj new file mode 100644 index 0000000..437f352 --- /dev/null +++ b/JCPrinterSDK.xcodeproj/project.pbxproj @@ -0,0 +1,412 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 177B44812AE424F9001E3EE6 /* JCPrinterSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 177B44802AE424F9001E3EE6 /* JCPrinterSDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 177B448D2AE42549001E3EE6 /* FWnetworkWIFI.mm in Sources */ = {isa = PBXBuildFile; fileRef = 177B44872AE42549001E3EE6 /* FWnetworkWIFI.mm */; }; + 177B448E2AE42549001E3EE6 /* JCAPI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 177B44882AE42549001E3EE6 /* JCAPI.a */; }; + 177B448F2AE42549001E3EE6 /* JCAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 177B44892AE42549001E3EE6 /* JCAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 177B44902AE42549001E3EE6 /* FWnetworkWIFI.h in Headers */ = {isa = PBXBuildFile; fileRef = 177B448A2AE42549001E3EE6 /* FWnetworkWIFI.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 177B44952AE425A3001E3EE6 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 177B44942AE425A3001E3EE6 /* AVFoundation.framework */; }; + 177B44972AE425B5001E3EE6 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 177B44962AE425B5001E3EE6 /* CoreMedia.framework */; }; + 177B449B2AE42605001E3EE6 /* JCSDKPringterConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = 177B449A2AE42605001E3EE6 /* JCSDKPringterConfig.json */; }; + 177B44B32AE42892001E3EE6 /* libbz2.1.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 177B44982AE425BF001E3EE6 /* libbz2.1.0.tbd */; }; + 177B44B42AE42899001E3EE6 /* libiconv.2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 177B44992AE425CE001E3EE6 /* libiconv.2.tbd */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 177B447D2AE424F9001E3EE6 /* JCPrinterSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JCPrinterSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 177B44802AE424F9001E3EE6 /* JCPrinterSDK.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JCPrinterSDK.h; sourceTree = ""; }; + 177B44872AE42549001E3EE6 /* FWnetworkWIFI.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FWnetworkWIFI.mm; sourceTree = ""; }; + 177B44882AE42549001E3EE6 /* JCAPI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = JCAPI.a; sourceTree = ""; }; + 177B44892AE42549001E3EE6 /* JCAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCAPI.h; sourceTree = ""; }; + 177B448A2AE42549001E3EE6 /* FWnetworkWIFI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FWnetworkWIFI.h; sourceTree = ""; }; + 177B448C2AE42549001E3EE6 /* Source */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Source; sourceTree = ""; }; + 177B44942AE425A3001E3EE6 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; + 177B44962AE425B5001E3EE6 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/System/Library/Frameworks/CoreMedia.framework; sourceTree = DEVELOPER_DIR; }; + 177B44982AE425BF001E3EE6 /* libbz2.1.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.1.0.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/usr/lib/libbz2.1.0.tbd; sourceTree = DEVELOPER_DIR; }; + 177B44992AE425CE001E3EE6 /* libiconv.2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.2.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/usr/lib/libiconv.2.tbd; sourceTree = DEVELOPER_DIR; }; + 177B449A2AE42605001E3EE6 /* JCSDKPringterConfig.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = JCSDKPringterConfig.json; path = JCPrinterSDK/Source/JCSDKPringterConfig.json; sourceTree = ""; }; + 177B44C52AE42D5F001E3EE6 /* CocoaAsyncSocket.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CocoaAsyncSocket.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 177B447A2AE424F9001E3EE6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 177B44B42AE42899001E3EE6 /* libiconv.2.tbd in Frameworks */, + 177B44972AE425B5001E3EE6 /* CoreMedia.framework in Frameworks */, + 177B44B32AE42892001E3EE6 /* libbz2.1.0.tbd in Frameworks */, + 177B44952AE425A3001E3EE6 /* AVFoundation.framework in Frameworks */, + 177B448E2AE42549001E3EE6 /* JCAPI.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 177B44732AE424F9001E3EE6 = { + isa = PBXGroup; + children = ( + 177B449A2AE42605001E3EE6 /* JCSDKPringterConfig.json */, + 177B447F2AE424F9001E3EE6 /* JCPrinterSDK */, + 177B447E2AE424F9001E3EE6 /* Products */, + 177B44932AE425A3001E3EE6 /* Frameworks */, + ); + sourceTree = ""; + }; + 177B447E2AE424F9001E3EE6 /* Products */ = { + isa = PBXGroup; + children = ( + 177B447D2AE424F9001E3EE6 /* JCPrinterSDK.framework */, + ); + name = Products; + sourceTree = ""; + }; + 177B447F2AE424F9001E3EE6 /* JCPrinterSDK */ = { + isa = PBXGroup; + children = ( + 177B44C52AE42D5F001E3EE6 /* CocoaAsyncSocket.framework */, + 177B448A2AE42549001E3EE6 /* FWnetworkWIFI.h */, + 177B44872AE42549001E3EE6 /* FWnetworkWIFI.mm */, + 177B44882AE42549001E3EE6 /* JCAPI.a */, + 177B44892AE42549001E3EE6 /* JCAPI.h */, + 177B448C2AE42549001E3EE6 /* Source */, + 177B44802AE424F9001E3EE6 /* JCPrinterSDK.h */, + ); + path = JCPrinterSDK; + sourceTree = ""; + }; + 177B44932AE425A3001E3EE6 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 177B44982AE425BF001E3EE6 /* libbz2.1.0.tbd */, + 177B44992AE425CE001E3EE6 /* libiconv.2.tbd */, + 177B44962AE425B5001E3EE6 /* CoreMedia.framework */, + 177B44942AE425A3001E3EE6 /* AVFoundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 177B44782AE424F9001E3EE6 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 177B44902AE42549001E3EE6 /* FWnetworkWIFI.h in Headers */, + 177B448F2AE42549001E3EE6 /* JCAPI.h in Headers */, + 177B44812AE424F9001E3EE6 /* JCPrinterSDK.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 177B447C2AE424F9001E3EE6 /* JCPrinterSDK */ = { + isa = PBXNativeTarget; + buildConfigurationList = 177B44842AE424F9001E3EE6 /* Build configuration list for PBXNativeTarget "JCPrinterSDK" */; + buildPhases = ( + 177B44782AE424F9001E3EE6 /* Headers */, + 177B44792AE424F9001E3EE6 /* Sources */, + 177B447A2AE424F9001E3EE6 /* Frameworks */, + 177B447B2AE424F9001E3EE6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = JCPrinterSDK; + productName = JCPrinterSDK; + productReference = 177B447D2AE424F9001E3EE6 /* JCPrinterSDK.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 177B44742AE424F9001E3EE6 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1500; + TargetAttributes = { + 177B447C2AE424F9001E3EE6 = { + CreatedOnToolsVersion = 15.0.1; + }; + }; + }; + buildConfigurationList = 177B44772AE424F9001E3EE6 /* Build configuration list for PBXProject "JCPrinterSDK" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 177B44732AE424F9001E3EE6; + productRefGroup = 177B447E2AE424F9001E3EE6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 177B447C2AE424F9001E3EE6 /* JCPrinterSDK */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 177B447B2AE424F9001E3EE6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 177B449B2AE42605001E3EE6 /* JCSDKPringterConfig.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 177B44792AE424F9001E3EE6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 177B448D2AE42549001E3EE6 /* FWnetworkWIFI.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 177B44822AE424F9001E3EE6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 177B44832AE424F9001E3EE6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 177B44852AE424F9001E3EE6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/JCPrinterSDK", + "$(PROJECT_DIR)", + ); + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/JCPrinterSDK", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = cc.nasme.JCPrinterSDK; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 177B44862AE424F9001E3EE6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/JCPrinterSDK", + "$(PROJECT_DIR)", + ); + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/JCPrinterSDK", + ); + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = cc.nasme.JCPrinterSDK; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 177B44772AE424F9001E3EE6 /* Build configuration list for PBXProject "JCPrinterSDK" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 177B44822AE424F9001E3EE6 /* Debug */, + 177B44832AE424F9001E3EE6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 177B44842AE424F9001E3EE6 /* Build configuration list for PBXNativeTarget "JCPrinterSDK" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 177B44852AE424F9001E3EE6 /* Debug */, + 177B44862AE424F9001E3EE6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 177B44742AE424F9001E3EE6 /* Project object */; +} diff --git a/JCPrinterSDK.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JCPrinterSDK.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/JCPrinterSDK.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/JCPrinterSDK.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/JCPrinterSDK.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/JCPrinterSDK.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/JCPrinterSDK.xcodeproj/xcshareddata/xcschemes/JCPrinterSDK.xcscheme b/JCPrinterSDK.xcodeproj/xcshareddata/xcschemes/JCPrinterSDK.xcscheme new file mode 100644 index 0000000..b721015 --- /dev/null +++ b/JCPrinterSDK.xcodeproj/xcshareddata/xcschemes/JCPrinterSDK.xcscheme @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JCPrinterSDK.xcodeproj/xcuserdata/rean.xcuserdatad/xcschemes/xcschememanagement.plist b/JCPrinterSDK.xcodeproj/xcuserdata/rean.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..9a791b7 --- /dev/null +++ b/JCPrinterSDK.xcodeproj/xcuserdata/rean.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + JCPrinterSDK.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + 177B447C2AE424F9001E3EE6 + + primary + + + + + diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/CocoaAsyncSocket b/JCPrinterSDK/CocoaAsyncSocket.framework/CocoaAsyncSocket new file mode 100644 index 0000000..31e3d7b Binary files /dev/null and b/JCPrinterSDK/CocoaAsyncSocket.framework/CocoaAsyncSocket differ diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/AsyncSocket.h b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/AsyncSocket.h new file mode 100644 index 0000000..335166b --- /dev/null +++ b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/AsyncSocket.h @@ -0,0 +1,657 @@ +// +// AsyncSocket.h +// +// This class is in the public domain. +// Originally created by Dustin Voss on Wed Jan 29 2003. +// Updated and maintained by Deusty Designs and the Mac development community. +// +// http://code.google.com/p/cocoaasyncsocket/ +// + +#import + +@class AsyncSocket; +@class AsyncReadPacket; +@class AsyncWritePacket; + +extern NSString *const AsyncSocketException; +extern NSString *const AsyncSocketErrorDomain; + +typedef NS_ENUM(NSInteger, AsyncSocketError) { + AsyncSocketCFSocketError = kCFSocketError, // From CFSocketError enum. + AsyncSocketNoError = 0, // Never used. + AsyncSocketCanceledError, // onSocketWillConnect: returned NO. + AsyncSocketConnectTimeoutError, + AsyncSocketReadMaxedOutError, // Reached set maxLength without completing + AsyncSocketReadTimeoutError, + AsyncSocketWriteTimeoutError +}; + +@protocol AsyncSocketDelegate +@optional + +/** + * In the event of an error, the socket is closed. + * You may call "unreadData" during this call-back to get the last bit of data off the socket. + * When connecting, this delegate method may be called + * before"onSocket:didAcceptNewSocket:" or "onSocket:didConnectToHost:". +**/ +- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err; + +/** + * Called when a socket disconnects with or without error. If you want to release a socket after it disconnects, + * do so here. It is not safe to do that during "onSocket:willDisconnectWithError:". + * + * If you call the disconnect method, and the socket wasn't already disconnected, + * this delegate method will be called before the disconnect method returns. +**/ +- (void)onSocketDidDisconnect:(AsyncSocket *)sock; + +/** + * Called when a socket accepts a connection. Another socket is spawned to handle it. The new socket will have + * the same delegate and will call "onSocket:didConnectToHost:port:". +**/ +- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket; + +/** + * Called when a new socket is spawned to handle a connection. This method should return the run-loop of the + * thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used. +**/ +- (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket; + +/** + * Called when a socket is about to connect. This method should return YES to continue, or NO to abort. + * If aborted, will result in AsyncSocketCanceledError. + * + * If the connectToHost:onPort:error: method was called, the delegate will be able to access and configure the + * CFReadStream and CFWriteStream as desired prior to connection. + * + * If the connectToAddress:error: method was called, the delegate will be able to access and configure the + * CFSocket and CFSocketNativeHandle (BSD socket) as desired prior to connection. You will be able to access and + * configure the CFReadStream and CFWriteStream in the onSocket:didConnectToHost:port: method. +**/ +- (BOOL)onSocketWillConnect:(AsyncSocket *)sock; + +/** + * Called when a socket connects and is ready for reading and writing. + * The host parameter will be an IP address, not a DNS name. +**/ +- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port; + +/** + * Called when a socket has completed reading the requested data into memory. + * Not called if there is an error. +**/ +- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag; + +/** + * Called when a socket has read in data, but has not yet completed the read. + * This would occur if using readToData: or readToLength: methods. + * It may be used to for things such as updating progress bars. +**/ +- (void)onSocket:(AsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; + +/** + * Called when a socket has completed writing the requested data. Not called if there is an error. +**/ +- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag; + +/** + * Called when a socket has written some data, but has not yet completed the entire write. + * It may be used to for things such as updating progress bars. +**/ +- (void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; + +/** + * Called if a read operation has reached its timeout without completing. + * This method allows you to optionally extend the timeout. + * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount. + * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual. + * + * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. + * The length parameter is the number of bytes that have been read so far for the read operation. + * + * Note that this method may be called multiple times for a single read if you return positive numbers. +**/ +- (NSTimeInterval)onSocket:(AsyncSocket *)sock + shouldTimeoutReadWithTag:(long)tag + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; + +/** + * Called if a write operation has reached its timeout without completing. + * This method allows you to optionally extend the timeout. + * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount. + * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual. + * + * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. + * The length parameter is the number of bytes that have been written so far for the write operation. + * + * Note that this method may be called multiple times for a single write if you return positive numbers. +**/ +- (NSTimeInterval)onSocket:(AsyncSocket *)sock + shouldTimeoutWriteWithTag:(long)tag + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; + +/** + * Called after the socket has successfully completed SSL/TLS negotiation. + * This method is not called unless you use the provided startTLS method. + * + * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close, + * and the onSocket:willDisconnectWithError: delegate method will be called with the specific SSL error code. +**/ +- (void)onSocketDidSecure:(AsyncSocket *)sock; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface AsyncSocket : NSObject +{ + CFSocketNativeHandle theNativeSocket4; + CFSocketNativeHandle theNativeSocket6; + + CFSocketRef theSocket4; // IPv4 accept or connect socket + CFSocketRef theSocket6; // IPv6 accept or connect socket + + CFReadStreamRef theReadStream; + CFWriteStreamRef theWriteStream; + + CFRunLoopSourceRef theSource4; // For theSocket4 + CFRunLoopSourceRef theSource6; // For theSocket6 + CFRunLoopRef theRunLoop; + CFSocketContext theContext; + NSArray *theRunLoopModes; + + NSTimer *theConnectTimer; + + NSMutableArray *theReadQueue; + AsyncReadPacket *theCurrentRead; + NSTimer *theReadTimer; + NSMutableData *partialReadBuffer; + + NSMutableArray *theWriteQueue; + AsyncWritePacket *theCurrentWrite; + NSTimer *theWriteTimer; + + id theDelegate; + UInt16 theFlags; + + long theUserData; +} + +- (id)init; +- (id)initWithDelegate:(id)delegate; +- (id)initWithDelegate:(id)delegate userData:(long)userData; + +/* String representation is long but has no "\n". */ +- (NSString *)description; + +/** + * Use "canSafelySetDelegate" to see if there is any pending business (reads and writes) with the current delegate + * before changing it. It is, of course, safe to change the delegate before connecting or accepting connections. +**/ +- (id)delegate; +- (BOOL)canSafelySetDelegate; +- (void)setDelegate:(id)delegate; + +/* User data can be a long, or an id or void * cast to a long. */ +- (long)userData; +- (void)setUserData:(long)userData; + +/* Don't use these to read or write. And don't close them either! */ +- (CFSocketRef)getCFSocket; +- (CFReadStreamRef)getCFReadStream; +- (CFWriteStreamRef)getCFWriteStream; + +// Once one of the accept or connect methods are called, the AsyncSocket instance is locked in +// and the other accept/connect methods can't be called without disconnecting the socket first. +// If the attempt fails or times out, these methods either return NO or +// call "onSocket:willDisconnectWithError:" and "onSockedDidDisconnect:". + +// When an incoming connection is accepted, AsyncSocket invokes several delegate methods. +// These methods are (in chronological order): +// 1. onSocket:didAcceptNewSocket: +// 2. onSocket:wantsRunLoopForNewSocket: +// 3. onSocketWillConnect: +// +// Your server code will need to retain the accepted socket (if you want to accept it). +// The best place to do this is probably in the onSocket:didAcceptNewSocket: method. +// +// After the read and write streams have been setup for the newly accepted socket, +// the onSocket:didConnectToHost:port: method will be called on the proper run loop. +// +// Multithreading Note: If you're going to be moving the newly accepted socket to another run +// loop by implementing onSocket:wantsRunLoopForNewSocket:, then you should wait until the +// onSocket:didConnectToHost:port: method before calling read, write, or startTLS methods. +// Otherwise read/write events are scheduled on the incorrect runloop, and chaos may ensue. + +/** + * Tells the socket to begin listening and accepting connections on the given port. + * When a connection comes in, the AsyncSocket instance will call the various delegate methods (see above). + * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) +**/ +- (BOOL)acceptOnPort:(UInt16)port error:(NSError **)errPtr; + +/** + * This method is the same as acceptOnPort:error: with the additional option + * of specifying which interface to listen on. So, for example, if you were writing code for a server that + * has multiple IP addresses, you could specify which address you wanted to listen on. Or you could use it + * to specify that the socket should only accept connections over ethernet, and not other interfaces such as wifi. + * You may also use the special strings "localhost" or "loopback" to specify that + * the socket only accept connections from the local machine. + * + * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method. +**/ +- (BOOL)acceptOnInterface:(NSString *)interface port:(UInt16)port error:(NSError **)errPtr; + +/** + * Connects to the given host and port. + * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2") +**/ +- (BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error:(NSError **)errPtr; + +/** + * This method is the same as connectToHost:onPort:error: with an additional timeout option. + * To not time out use a negative time interval, or simply use the connectToHost:onPort:error: method. +**/ +- (BOOL)connectToHost:(NSString *)hostname + onPort:(UInt16)port + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +/** + * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object. + * For example, a NSData object returned from NSNetService's addresses method. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; + +/** + * This method is the same as connectToAddress:error: with an additional timeout option. + * To not time out use a negative time interval, or simply use the connectToAddress:error: method. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr; + +- (BOOL)connectToAddress:(NSData *)remoteAddr + viaInterfaceAddress:(NSData *)interfaceAddr + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +/** + * Disconnects immediately. Any pending reads or writes are dropped. + * If the socket is not already disconnected, the onSocketDidDisconnect delegate method + * will be called immediately, before this method returns. + * + * Please note the recommended way of releasing an AsyncSocket instance (e.g. in a dealloc method) + * [asyncSocket setDelegate:nil]; + * [asyncSocket disconnect]; + * [asyncSocket release]; +**/ +- (void)disconnect; + +/** + * Disconnects after all pending reads have completed. + * After calling this, the read and write methods will do nothing. + * The socket will disconnect even if there are still pending writes. +**/ +- (void)disconnectAfterReading; + +/** + * Disconnects after all pending writes have completed. + * After calling this, the read and write methods will do nothing. + * The socket will disconnect even if there are still pending reads. +**/ +- (void)disconnectAfterWriting; + +/** + * Disconnects after all pending reads and writes have completed. + * After calling this, the read and write methods will do nothing. +**/ +- (void)disconnectAfterReadingAndWriting; + +/* Returns YES if the socket and streams are open, connected, and ready for reading and writing. */ +- (BOOL)isConnected; + +/** + * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected. + * The host will be an IP address. +**/ +- (NSString *)connectedHost; +- (UInt16)connectedPort; + +- (NSString *)localHost; +- (UInt16)localPort; + +/** + * Returns the local or remote address to which this socket is connected, + * specified as a sockaddr structure wrapped in a NSData object. + * + * See also the connectedHost, connectedPort, localHost and localPort methods. +**/ +- (NSData *)connectedAddress; +- (NSData *)localAddress; + +/** + * Returns whether the socket is IPv4 or IPv6. + * An accepting socket may be both. +**/ +- (BOOL)isIPv4; +- (BOOL)isIPv6; + +// The readData and writeData methods won't block (they are asynchronous). +// +// When a read is complete the onSocket:didReadData:withTag: delegate method is called. +// When a write is complete the onSocket:didWriteDataWithTag: delegate method is called. +// +// You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.) +// If a read/write opertion times out, the corresponding "onSocket:shouldTimeout..." delegate method +// is called to optionally allow you to extend the timeout. +// Upon a timeout, the "onSocket:willDisconnectWithError:" method is called, followed by "onSocketDidDisconnect". +// +// The tag is for your convenience. +// You can use it as an array index, step number, state id, pointer, etc. + +/** + * Reads the first available bytes that become available on the socket. + * + * If the timeout value is negative, the read operation will not use a timeout. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads the first available bytes that become available on the socket. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, the socket will create a buffer for you. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. + * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads the first available bytes that become available on the socket. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * A maximum of length bytes will be read. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * If maxLength is zero, no length restriction is enforced. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. + * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag; + +/** + * Reads the given number of bytes. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If the length is 0, this method does nothing and the delegate is not called. +**/ +- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads the given number of bytes. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If the length is 0, this method does nothing and the delegate is not called. + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. + * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer. +**/ +- (void)readDataToLength:(NSUInteger)length + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If you pass nil or zero-length data as the "data" parameter, + * the method will do nothing, and the delegate will not be called. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for + * a character, the read will prematurely end. +**/ +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. + * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for + * a character, the read will prematurely end. +**/ +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If maxLength is zero, no length restriction is enforced. + * Otherwise if maxLength bytes are read without completing the read, + * it is treated similarly to a timeout - the socket is closed with a AsyncSocketReadMaxedOutError. + * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. + * + * If you pass nil or zero-length data as the "data" parameter, + * the method will do nothing, and the delegate will not be called. + * If you pass a maxLength parameter that is less than the length of the data parameter, + * the method will do nothing, and the delegate will not be called. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for + * a character, the read will prematurely end. +**/ +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * A maximum of length bytes will be read. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If maxLength is zero, no length restriction is enforced. + * Otherwise if maxLength bytes are read without completing the read, + * it is treated similarly to a timeout - the socket is closed with a AsyncSocketReadMaxedOutError. + * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. + * + * If you pass a maxLength parameter that is less than the length of the data parameter, + * the method will do nothing, and the delegate will not be called. + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. + * After completion, the data returned in onSocket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * Note that this method is not character-set aware, so if a separator can occur naturally as part of the encoding for + * a character, the read will prematurely end. +**/ +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag; + +/** + * Writes data to the socket, and calls the delegate when finished. + * + * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called. + * If the timeout value is negative, the write operation will not use a timeout. +**/ +- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Returns progress of current read or write, from 0.0 to 1.0, or NaN if no read/write (use isnan() to check). + * "tag", "done" and "total" will be filled in if they aren't NULL. +**/ +- (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total; +- (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total; + +/** + * Secures the connection using SSL/TLS. + * + * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes + * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing + * the upgrade to TLS at the same time, without having to wait for the write to finish. + * Any reads or writes scheduled after this method is called will occur over the secured connection. + * + * The possible keys and values for the TLS settings are well documented. + * Some possible keys are: + * - kCFStreamSSLLevel + * - kCFStreamSSLAllowsExpiredCertificates + * - kCFStreamSSLAllowsExpiredRoots + * - kCFStreamSSLAllowsAnyRoot + * - kCFStreamSSLValidatesCertificateChain + * - kCFStreamSSLPeerName + * - kCFStreamSSLCertificates + * - kCFStreamSSLIsServer + * + * Please refer to Apple's documentation for associated values, as well as other possible keys. + * + * If you pass in nil or an empty dictionary, the default settings will be used. + * + * The default settings will check to make sure the remote party's certificate is signed by a + * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired. + * However it will not verify the name on the certificate unless you + * give it a name to verify against via the kCFStreamSSLPeerName key. + * The security implications of this are important to understand. + * Imagine you are attempting to create a secure connection to MySecureServer.com, + * but your socket gets directed to MaliciousServer.com because of a hacked DNS server. + * If you simply use the default settings, and MaliciousServer.com has a valid certificate, + * the default settings will not detect any problems since the certificate is valid. + * To properly secure your connection in this particular scenario you + * should set the kCFStreamSSLPeerName property to "MySecureServer.com". + * If you do not know the peer name of the remote host in advance (for example, you're not sure + * if it will be "domain.com" or "www.domain.com"), then you can use the default settings to validate the + * certificate, and then use the X509Certificate class to verify the issuer after the socket has been secured. + * The X509Certificate class is part of the CocoaAsyncSocket open source project. +**/ +- (void)startTLS:(NSDictionary *)tlsSettings; + +/** + * For handling readDataToData requests, data is necessarily read from the socket in small increments. + * The performance can be much improved by allowing AsyncSocket to read larger chunks at a time and + * store any overflow in a small internal buffer. + * This is termed pre-buffering, as some data may be read for you before you ask for it. + * If you use readDataToData a lot, enabling pre-buffering will result in better performance, especially on the iPhone. + * + * The default pre-buffering state is controlled by the DEFAULT_PREBUFFERING definition. + * It is highly recommended one leave this set to YES. + * + * This method exists in case pre-buffering needs to be disabled by default for some unforeseen reason. + * In that case, this method exists to allow one to easily enable pre-buffering when ready. +**/ +- (void)enablePreBuffering; + +/** + * When you create an AsyncSocket, it is added to the runloop of the current thread. + * So for manually created sockets, it is easiest to simply create the socket on the thread you intend to use it. + * + * If a new socket is accepted, the delegate method onSocket:wantsRunLoopForNewSocket: is called to + * allow you to place the socket on a separate thread. This works best in conjunction with a thread pool design. + * + * If, however, you need to move the socket to a separate thread at a later time, this + * method may be used to accomplish the task. + * + * This method must be called from the thread/runloop the socket is currently running on. + * + * Note: After calling this method, all further method calls to this object should be done from the given runloop. + * Also, all delegate calls will be sent on the given runloop. +**/ +- (BOOL)moveToRunLoop:(NSRunLoop *)runLoop; + +/** + * Allows you to configure which run loop modes the socket uses. + * The default set of run loop modes is NSDefaultRunLoopMode. + * + * If you'd like your socket to continue operation during other modes, you may want to add modes such as + * NSModalPanelRunLoopMode or NSEventTrackingRunLoopMode. Or you may simply want to use NSRunLoopCommonModes. + * + * Accepted sockets will automatically inherit the same run loop modes as the listening socket. + * + * Note: NSRunLoopCommonModes is defined in 10.5. For previous versions one can use kCFRunLoopCommonModes. +**/ +- (BOOL)setRunLoopModes:(NSArray *)runLoopModes; +- (BOOL)addRunLoopMode:(NSString *)runLoopMode; +- (BOOL)removeRunLoopMode:(NSString *)runLoopMode; + +/** + * Returns the current run loop modes the AsyncSocket instance is operating in. + * The default set of run loop modes is NSDefaultRunLoopMode. +**/ +- (NSArray *)runLoopModes; + +/** + * In the event of an error, this method may be called during onSocket:willDisconnectWithError: to read + * any data that's left on the socket. +**/ +- (NSData *)unreadData; + +/* A few common line separators, for use with the readDataToData:... methods. */ ++ (NSData *)CRLFData; // 0x0D0A ++ (NSData *)CRData; // 0x0D ++ (NSData *)LFData; // 0x0A ++ (NSData *)ZeroData; // 0x00 + +@end diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/AsyncUdpSocket.h b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/AsyncUdpSocket.h new file mode 100644 index 0000000..7bacef4 --- /dev/null +++ b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/AsyncUdpSocket.h @@ -0,0 +1,368 @@ +// +// AsyncUdpSocket.h +// +// This class is in the public domain. +// Originally created by Robbie Hanson on Wed Oct 01 2008. +// Updated and maintained by Deusty Designs and the Mac development community. +// +// http://code.google.com/p/cocoaasyncsocket/ +// + +#import + +@class AsyncSendPacket; +@class AsyncReceivePacket; + +extern NSString *const AsyncUdpSocketException; +extern NSString *const AsyncUdpSocketErrorDomain; + +typedef NS_ENUM(NSInteger, AsyncUdpSocketError) { + AsyncUdpSocketCFSocketError = kCFSocketError, // From CFSocketError enum + AsyncUdpSocketNoError = 0, // Never used + AsyncUdpSocketBadParameter, // Used if given a bad parameter (such as an improper address) + AsyncUdpSocketIPv4Unavailable, // Used if you bind/connect using IPv6 only + AsyncUdpSocketIPv6Unavailable, // Used if you bind/connect using IPv4 only (or iPhone) + AsyncUdpSocketSendTimeoutError, + AsyncUdpSocketReceiveTimeoutError +}; + +@interface AsyncUdpSocket : NSObject +{ + CFSocketRef theSocket4; // IPv4 socket + CFSocketRef theSocket6; // IPv6 socket + + CFRunLoopSourceRef theSource4; // For theSocket4 + CFRunLoopSourceRef theSource6; // For theSocket6 + CFRunLoopRef theRunLoop; + CFSocketContext theContext; + NSArray *theRunLoopModes; + + NSMutableArray *theSendQueue; + AsyncSendPacket *theCurrentSend; + NSTimer *theSendTimer; + + NSMutableArray *theReceiveQueue; + AsyncReceivePacket *theCurrentReceive; + NSTimer *theReceiveTimer; + + id theDelegate; + UInt16 theFlags; + + long theUserData; + + NSString *cachedLocalHost; + UInt16 cachedLocalPort; + + NSString *cachedConnectedHost; + UInt16 cachedConnectedPort; + + UInt32 maxReceiveBufferSize; +} + +/** + * Creates new instances of AsyncUdpSocket. +**/ +- (id)init; +- (id)initWithDelegate:(id)delegate; +- (id)initWithDelegate:(id)delegate userData:(long)userData; + +/** + * Creates new instances of AsyncUdpSocket that support only IPv4 or IPv6. + * The other init methods will support both, unless specifically binded or connected to one protocol. + * If you know you'll only be using one protocol, these init methods may be a bit more efficient. +**/ +- (id)initIPv4; +- (id)initIPv6; + +- (id)delegate; +- (void)setDelegate:(id)delegate; + +- (long)userData; +- (void)setUserData:(long)userData; + +/** + * Returns the local address info for the socket. + * + * Note: Address info may not be available until after the socket has been bind'ed, + * or until after data has been sent. +**/ +- (NSString *)localHost; +- (UInt16)localPort; + +/** + * Returns the remote address info for the socket. + * + * Note: Since UDP is connectionless by design, connected address info + * will not be available unless the socket is explicitly connected to a remote host/port +**/ +- (NSString *)connectedHost; +- (UInt16)connectedPort; + +/** + * Returns whether or not this socket has been connected to a single host. + * By design, UDP is a connectionless protocol, and connecting is not needed. + * If connected, the socket will only be able to send/receive data to/from the connected host. +**/ +- (BOOL)isConnected; + +/** + * Returns whether or not this socket has been closed. + * The only way a socket can be closed is if you explicitly call one of the close methods. +**/ +- (BOOL)isClosed; + +/** + * Returns whether or not this socket supports IPv4. + * By default this will be true, unless the socket is specifically initialized as IPv6 only, + * or is binded or connected to an IPv6 address. +**/ +- (BOOL)isIPv4; + +/** + * Returns whether or not this socket supports IPv6. + * By default this will be true, unless the socket is specifically initialized as IPv4 only, + * or is binded or connected to an IPv4 address. + * + * This method will also return false on platforms that do not support IPv6. + * Note: The iPhone does not currently support IPv6. +**/ +- (BOOL)isIPv6; + +/** + * Returns the mtu of the socket. + * If unknown, returns zero. + * + * Sending data larger than this may result in an error. + * This is an advanced topic, and one should understand the wide range of mtu's on networks and the internet. + * Therefore this method is only for reference and may be of little use in many situations. +**/ +- (unsigned int)maximumTransmissionUnit; + +/** + * Binds the UDP socket to the given port and optional address. + * Binding should be done for server sockets that receive data prior to sending it. + * Client sockets can skip binding, + * as the OS will automatically assign the socket an available port when it starts sending data. + * + * You cannot bind a socket after its been connected. + * You can only bind a socket once. + * You can still connect a socket (if desired) after binding. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. +**/ +- (BOOL)bindToPort:(UInt16)port error:(NSError **)errPtr; +- (BOOL)bindToAddress:(NSString *)localAddr port:(UInt16)port error:(NSError **)errPtr; + +/** + * Connects the UDP socket to the given host and port. + * By design, UDP is a connectionless protocol, and connecting is not needed. + * + * Choosing to connect to a specific host/port has the following effect: + * - You will only be able to send data to the connected host/port. + * - You will only be able to receive data from the connected host/port. + * - You will receive ICMP messages that come from the connected host/port, such as "connection refused". + * + * Connecting a UDP socket does not result in any communication on the socket. + * It simply changes the internal state of the socket. + * + * You cannot bind a socket after its been connected. + * You can only connect a socket once. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. +**/ +- (BOOL)connectToHost:(NSString *)host onPort:(UInt16)port error:(NSError **)errPtr; +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; + +/** + * Join multicast group + * + * Group should be an IP address (eg @"225.228.0.1") +**/ +- (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr; +- (BOOL)joinMulticastGroup:(NSString *)group withAddress:(NSString *)interface error:(NSError **)errPtr; + +/** + * By default, the underlying socket in the OS will not allow you to send broadcast messages. + * In order to send broadcast messages, you need to enable this functionality in the socket. + * + * A broadcast is a UDP message to addresses like "192.168.255.255" or "255.255.255.255" that is + * delivered to every host on the network. + * The reason this is generally disabled by default is to prevent + * accidental broadcast messages from flooding the network. +**/ +- (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr; + +/** + * Asynchronously sends the given data, with the given timeout and tag. + * + * This method may only be used with a connected socket. + * + * If data is nil or zero-length, this method does nothing and immediately returns NO. + * If the socket is not connected, this method does nothing and immediately returns NO. +**/ +- (BOOL)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Asynchronously sends the given data, with the given timeout and tag, to the given host and port. + * + * This method cannot be used with a connected socket. + * + * If data is nil or zero-length, this method does nothing and immediately returns NO. + * If the socket is connected, this method does nothing and immediately returns NO. + * If unable to resolve host to a valid IPv4 or IPv6 address, this method returns NO. +**/ +- (BOOL)sendData:(NSData *)data toHost:(NSString *)host port:(UInt16)port withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Asynchronously sends the given data, with the given timeout and tag, to the given address. + * + * This method cannot be used with a connected socket. + * + * If data is nil or zero-length, this method does nothing and immediately returns NO. + * If the socket is connected, this method does nothing and immediately returns NO. +**/ +- (BOOL)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Asynchronously receives a single datagram packet. + * + * If the receive succeeds, the onUdpSocket:didReceiveData:fromHost:port:tag delegate method will be called. + * Otherwise, a timeout will occur, and the onUdpSocket:didNotReceiveDataWithTag: delegate method will be called. +**/ +- (void)receiveWithTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Closes the socket immediately. Any pending send or receive operations are dropped. +**/ +- (void)close; + +/** + * Closes after all pending send operations have completed. + * After calling this, the sendData: and receive: methods will do nothing. + * In other words, you won't be able to add any more send or receive operations to the queue. + * The socket will close even if there are still pending receive operations. +**/ +- (void)closeAfterSending; + +/** + * Closes after all pending receive operations have completed. + * After calling this, the sendData: and receive: methods will do nothing. + * In other words, you won't be able to add any more send or receive operations to the queue. + * The socket will close even if there are still pending send operations. +**/ +- (void)closeAfterReceiving; + +/** + * Closes after all pending send and receive operations have completed. + * After calling this, the sendData: and receive: methods will do nothing. + * In other words, you won't be able to add any more send or receive operations to the queue. +**/ +- (void)closeAfterSendingAndReceiving; + +/** + * Gets/Sets the maximum size of the buffer that will be allocated for receive operations. + * The default size is 9216 bytes. + * + * The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535. + * The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295. + * + * In practice, however, the size of UDP packets will be much smaller. + * Indeed most protocols will send and receive packets of only a few bytes, + * or will set a limit on the size of packets to prevent fragmentation in the IP layer. + * + * If you set the buffer size too small, the sockets API in the OS will silently discard + * any extra data, and you will not be notified of the error. +**/ +- (UInt32)maxReceiveBufferSize; +- (void)setMaxReceiveBufferSize:(UInt32)max; + +/** + * When you create an AsyncUdpSocket, it is added to the runloop of the current thread. + * So it is easiest to simply create the socket on the thread you intend to use it. + * + * If, however, you need to move the socket to a separate thread at a later time, this + * method may be used to accomplish the task. + * + * This method must be called from the thread/runloop the socket is currently running on. + * + * Note: After calling this method, all further method calls to this object should be done from the given runloop. + * Also, all delegate calls will be sent on the given runloop. +**/ +- (BOOL)moveToRunLoop:(NSRunLoop *)runLoop; + +/** + * Allows you to configure which run loop modes the socket uses. + * The default set of run loop modes is NSDefaultRunLoopMode. + * + * If you'd like your socket to continue operation during other modes, you may want to add modes such as + * NSModalPanelRunLoopMode or NSEventTrackingRunLoopMode. Or you may simply want to use NSRunLoopCommonModes. + * + * Note: NSRunLoopCommonModes is defined in 10.5. For previous versions one can use kCFRunLoopCommonModes. +**/ +- (BOOL)setRunLoopModes:(NSArray *)runLoopModes; + +/** + * Returns the current run loop modes the AsyncSocket instance is operating in. + * The default set of run loop modes is NSDefaultRunLoopMode. +**/ +- (NSArray *)runLoopModes; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol AsyncUdpSocketDelegate +@optional + +/** + * Called when the datagram with the given tag has been sent. +**/ +- (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag; + +/** + * Called if an error occurs while trying to send a datagram. + * This could be due to a timeout, or something more serious such as the data being too large to fit in a sigle packet. +**/ +- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error; + +/** + * Called when the socket has received the requested datagram. + * + * Due to the nature of UDP, you may occasionally receive undesired packets. + * These may be rogue UDP packets from unknown hosts, + * or they may be delayed packets arriving after retransmissions have already occurred. + * It's important these packets are properly ignored, while not interfering with the flow of your implementation. + * As an aid, this delegate method has a boolean return value. + * If you ever need to ignore a received packet, simply return NO, + * and AsyncUdpSocket will continue as if the packet never arrived. + * That is, the original receive request will still be queued, and will still timeout as usual if a timeout was set. + * For example, say you requested to receive data, and you set a timeout of 500 milliseconds, using a tag of 15. + * If rogue data arrives after 250 milliseconds, this delegate method would be invoked, and you could simply return NO. + * If the expected data then arrives within the next 250 milliseconds, + * this delegate method will be invoked, with a tag of 15, just as if the rogue data never appeared. + * + * Under normal circumstances, you simply return YES from this method. +**/ +- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock + didReceiveData:(NSData *)data + withTag:(long)tag + fromHost:(NSString *)host + port:(UInt16)port; + +/** + * Called if an error occurs while trying to receive a requested datagram. + * This is generally due to a timeout, but could potentially be something else if some kind of OS error occurred. +**/ +- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotReceiveDataWithTag:(long)tag dueToError:(NSError *)error; + +/** + * Called when the socket is closed. + * A socket is only closed if you explicitly call one of the close methods. +**/ +- (void)onUdpSocketDidClose:(AsyncUdpSocket *)sock; + +@end diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/CocoaAsyncSocket.h b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/CocoaAsyncSocket.h new file mode 100644 index 0000000..bac9e91 --- /dev/null +++ b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/CocoaAsyncSocket.h @@ -0,0 +1,20 @@ +// +// CocoaAsyncSocket.h +// CocoaAsyncSocket +// +// Created by Derek Clarkson on 10/08/2015. +// Copyright © 2015 Robbie Hanson. All rights reserved. +// + +@import Foundation; + +//! Project version number for CocoaAsyncSocket. +FOUNDATION_EXPORT double cocoaAsyncSocketVersionNumber; + +//! Project version string for CocoaAsyncSocket. +FOUNDATION_EXPORT const unsigned char cocoaAsyncSocketVersionString[]; + +#import +#import +#import +#import diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/GCDAsyncSocket.h b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/GCDAsyncSocket.h new file mode 100644 index 0000000..cf70095 --- /dev/null +++ b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/GCDAsyncSocket.h @@ -0,0 +1,1177 @@ +// +// GCDAsyncSocket.h +// +// This class is in the public domain. +// Originally created by Robbie Hanson in Q3 2010. +// Updated and maintained by Deusty LLC and the Apple development community. +// +// https://github.com/robbiehanson/CocoaAsyncSocket +// + +#import +#import +#import +#import +#import + +#include // AF_INET, AF_INET6 + +@class GCDAsyncReadPacket; +@class GCDAsyncWritePacket; +@class GCDAsyncSocketPreBuffer; + +extern NSString *const GCDAsyncSocketException; +extern NSString *const GCDAsyncSocketErrorDomain; + +extern NSString *const GCDAsyncSocketQueueName; +extern NSString *const GCDAsyncSocketThreadName; + +extern NSString *const GCDAsyncSocketManuallyEvaluateTrust; +#if TARGET_OS_IPHONE +extern NSString *const GCDAsyncSocketUseCFStreamForTLS; +#endif +#define GCDAsyncSocketSSLPeerName (NSString *)kCFStreamSSLPeerName +#define GCDAsyncSocketSSLCertificates (NSString *)kCFStreamSSLCertificates +#define GCDAsyncSocketSSLIsServer (NSString *)kCFStreamSSLIsServer +extern NSString *const GCDAsyncSocketSSLPeerID; +extern NSString *const GCDAsyncSocketSSLProtocolVersionMin; +extern NSString *const GCDAsyncSocketSSLProtocolVersionMax; +extern NSString *const GCDAsyncSocketSSLSessionOptionFalseStart; +extern NSString *const GCDAsyncSocketSSLSessionOptionSendOneByteRecord; +extern NSString *const GCDAsyncSocketSSLCipherSuites; +#if !TARGET_OS_IPHONE +extern NSString *const GCDAsyncSocketSSLDiffieHellmanParameters; +#endif + +#define GCDAsyncSocketLoggingContext 65535 + + +typedef NS_ENUM(NSInteger, GCDAsyncSocketError) { + GCDAsyncSocketNoError = 0, // Never used + GCDAsyncSocketBadConfigError, // Invalid configuration + GCDAsyncSocketBadParamError, // Invalid parameter was passed + GCDAsyncSocketConnectTimeoutError, // A connect operation timed out + GCDAsyncSocketReadTimeoutError, // A read operation timed out + GCDAsyncSocketWriteTimeoutError, // A write operation timed out + GCDAsyncSocketReadMaxedOutError, // Reached set maxLength without completing + GCDAsyncSocketClosedError, // The remote peer closed the connection + GCDAsyncSocketOtherError, // Description provided in userInfo +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface GCDAsyncSocket : NSObject + +/** + * GCDAsyncSocket uses the standard delegate paradigm, + * but executes all delegate callbacks on a given delegate dispatch queue. + * This allows for maximum concurrency, while at the same time providing easy thread safety. + * + * You MUST set a delegate AND delegate dispatch queue before attempting to + * use the socket, or you will get an error. + * + * The socket queue is optional. + * If you pass NULL, GCDAsyncSocket will automatically create it's own socket queue. + * If you choose to provide a socket queue, the socket queue must not be a concurrent queue. + * If you choose to provide a socket queue, and the socket queue has a configured target queue, + * then please see the discussion for the method markSocketQueueTargetQueue. + * + * The delegate queue and socket queue can optionally be the same. +**/ +- (id)init; +- (id)initWithSocketQueue:(dispatch_queue_t)sq; +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq; +- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq; + +#pragma mark Configuration + +@property (atomic, weak, readwrite) id delegate; +#if OS_OBJECT_USE_OBJC +@property (atomic, strong, readwrite) dispatch_queue_t delegateQueue; +#else +@property (atomic, assign, readwrite) dispatch_queue_t delegateQueue; +#endif + +- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr; +- (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue; + +/** + * If you are setting the delegate to nil within the delegate's dealloc method, + * you may need to use the synchronous versions below. +**/ +- (void)synchronouslySetDelegate:(id)delegate; +- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue; + +/** + * By default, both IPv4 and IPv6 are enabled. + * + * For accepting incoming connections, this means GCDAsyncSocket automatically supports both protocols, + * and can simulataneously accept incoming connections on either protocol. + * + * For outgoing connections, this means GCDAsyncSocket can connect to remote hosts running either protocol. + * If a DNS lookup returns only IPv4 results, GCDAsyncSocket will automatically use IPv4. + * If a DNS lookup returns only IPv6 results, GCDAsyncSocket will automatically use IPv6. + * If a DNS lookup returns both IPv4 and IPv6 results, the preferred protocol will be chosen. + * By default, the preferred protocol is IPv4, but may be configured as desired. +**/ + +@property (atomic, assign, readwrite, getter=isIPv4Enabled) BOOL IPv4Enabled; +@property (atomic, assign, readwrite, getter=isIPv6Enabled) BOOL IPv6Enabled; + +@property (atomic, assign, readwrite, getter=isIPv4PreferredOverIPv6) BOOL IPv4PreferredOverIPv6; + +/** + * User data allows you to associate arbitrary information with the socket. + * This data is not used internally by socket in any way. +**/ +@property (atomic, strong, readwrite) id userData; + +#pragma mark Accepting + +/** + * Tells the socket to begin listening and accepting connections on the given port. + * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it, + * and the socket:didAcceptNewSocket: delegate method will be invoked. + * + * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc) +**/ +- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * This method is the same as acceptOnPort:error: with the + * additional option of specifying which interface to listen on. + * + * For example, you could specify that the socket should only accept connections over ethernet, + * and not other interfaces such as wifi. + * + * The interface may be specified by name (e.g. "en1" or "lo0") or by IP address (e.g. "192.168.4.34"). + * You may also use the special strings "localhost" or "loopback" to specify that + * the socket only accept connections from the local machine. + * + * You can see the list of interfaces via the command line utility "ifconfig", + * or programmatically via the getifaddrs() function. + * + * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method. +**/ +- (BOOL)acceptOnInterface:(NSString *)interface port:(uint16_t)port error:(NSError **)errPtr; + +#pragma mark Connecting + +/** + * Connects to the given host and port. + * + * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: + * and uses the default interface, and no timeout. +**/ +- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * Connects to the given host and port with an optional timeout. + * + * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: and uses the default interface. +**/ +- (BOOL)connectToHost:(NSString *)host + onPort:(uint16_t)port + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +/** + * Connects to the given host & port, via the optional interface, with an optional timeout. + * + * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). + * The host may also be the special strings "localhost" or "loopback" to specify connecting + * to a service on the local machine. + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * The interface may also be used to specify the local port (see below). + * + * To not time out use a negative time interval. + * + * This method will return NO if an error is detected, and set the error pointer (if one was given). + * Possible errors would be a nil host, invalid interface, or socket is already connected. + * + * If no errors are detected, this method will start a background connect operation and immediately return YES. + * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. + * + * Since this class supports queued reads and writes, you can immediately start reading and/or writing. + * All read/write operations will be queued, and upon socket connection, + * the operations will be dequeued and processed in order. + * + * The interface may optionally contain a port number at the end of the string, separated by a colon. + * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) + * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". + * To specify only local port: ":8082". + * Please note this is an advanced feature, and is somewhat hidden on purpose. + * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. + * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. + * Local ports do NOT need to match remote ports. In fact, they almost never do. + * This feature is here for networking professionals using very advanced techniques. +**/ +- (BOOL)connectToHost:(NSString *)host + onPort:(uint16_t)port + viaInterface:(NSString *)interface + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +/** + * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object. + * For example, a NSData object returned from NSNetService's addresses method. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * This method invokes connectToAdd +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; + +/** + * This method is the same as connectToAddress:error: with an additional timeout option. + * To not time out use a negative time interval, or simply use the connectToAddress:error: method. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr; + +/** + * Connects to the given address, using the specified interface and timeout. + * + * The address is specified as a sockaddr structure wrapped in a NSData object. + * For example, a NSData object returned from NSNetService's addresses method. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * The interface may also be used to specify the local port (see below). + * + * The timeout is optional. To not time out use a negative time interval. + * + * This method will return NO if an error is detected, and set the error pointer (if one was given). + * Possible errors would be a nil host, invalid interface, or socket is already connected. + * + * If no errors are detected, this method will start a background connect operation and immediately return YES. + * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable. + * + * Since this class supports queued reads and writes, you can immediately start reading and/or writing. + * All read/write operations will be queued, and upon socket connection, + * the operations will be dequeued and processed in order. + * + * The interface may optionally contain a port number at the end of the string, separated by a colon. + * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end) + * To specify both interface and local port: "en1:8082" or "192.168.4.35:2424". + * To specify only local port: ":8082". + * Please note this is an advanced feature, and is somewhat hidden on purpose. + * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection. + * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere. + * Local ports do NOT need to match remote ports. In fact, they almost never do. + * This feature is here for networking professionals using very advanced techniques. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr + viaInterface:(NSString *)interface + withTimeout:(NSTimeInterval)timeout + error:(NSError **)errPtr; + +#pragma mark Disconnecting + +/** + * Disconnects immediately (synchronously). Any pending reads or writes are dropped. + * + * If the socket is not already disconnected, an invocation to the socketDidDisconnect:withError: delegate method + * will be queued onto the delegateQueue asynchronously (behind any previously queued delegate methods). + * In other words, the disconnected delegate method will be invoked sometime shortly after this method returns. + * + * Please note the recommended way of releasing a GCDAsyncSocket instance (e.g. in a dealloc method) + * [asyncSocket setDelegate:nil]; + * [asyncSocket disconnect]; + * [asyncSocket release]; + * + * If you plan on disconnecting the socket, and then immediately asking it to connect again, + * you'll likely want to do so like this: + * [asyncSocket setDelegate:nil]; + * [asyncSocket disconnect]; + * [asyncSocket setDelegate:self]; + * [asyncSocket connect...]; +**/ +- (void)disconnect; + +/** + * Disconnects after all pending reads have completed. + * After calling this, the read and write methods will do nothing. + * The socket will disconnect even if there are still pending writes. +**/ +- (void)disconnectAfterReading; + +/** + * Disconnects after all pending writes have completed. + * After calling this, the read and write methods will do nothing. + * The socket will disconnect even if there are still pending reads. +**/ +- (void)disconnectAfterWriting; + +/** + * Disconnects after all pending reads and writes have completed. + * After calling this, the read and write methods will do nothing. +**/ +- (void)disconnectAfterReadingAndWriting; + +#pragma mark Diagnostics + +/** + * Returns whether the socket is disconnected or connected. + * + * A disconnected socket may be recycled. + * That is, it can used again for connecting or listening. + * + * If a socket is in the process of connecting, it may be neither disconnected nor connected. +**/ +@property (atomic, readonly) BOOL isDisconnected; +@property (atomic, readonly) BOOL isConnected; + +/** + * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected. + * The host will be an IP address. +**/ +@property (atomic, readonly) NSString *connectedHost; +@property (atomic, readonly) uint16_t connectedPort; + +@property (atomic, readonly) NSString *localHost; +@property (atomic, readonly) uint16_t localPort; + +/** + * Returns the local or remote address to which this socket is connected, + * specified as a sockaddr structure wrapped in a NSData object. + * + * @seealso connectedHost + * @seealso connectedPort + * @seealso localHost + * @seealso localPort +**/ +@property (atomic, readonly) NSData *connectedAddress; +@property (atomic, readonly) NSData *localAddress; + +/** + * Returns whether the socket is IPv4 or IPv6. + * An accepting socket may be both. +**/ +@property (atomic, readonly) BOOL isIPv4; +@property (atomic, readonly) BOOL isIPv6; + +/** + * Returns whether or not the socket has been secured via SSL/TLS. + * + * See also the startTLS method. +**/ +@property (atomic, readonly) BOOL isSecure; + +#pragma mark Reading + +// The readData and writeData methods won't block (they are asynchronous). +// +// When a read is complete the socket:didReadData:withTag: delegate method is dispatched on the delegateQueue. +// When a write is complete the socket:didWriteDataWithTag: delegate method is dispatched on the delegateQueue. +// +// You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.) +// If a read/write opertion times out, the corresponding "socket:shouldTimeout..." delegate method +// is called to optionally allow you to extend the timeout. +// Upon a timeout, the "socket:didDisconnectWithError:" method is called +// +// The tag is for your convenience. +// You can use it as an array index, step number, state id, pointer, etc. + +/** + * Reads the first available bytes that become available on the socket. + * + * If the timeout value is negative, the read operation will not use a timeout. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads the first available bytes that become available on the socket. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, the socket will create a buffer for you. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads the first available bytes that become available on the socket. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * A maximum of length bytes will be read. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * If maxLength is zero, no length restriction is enforced. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (void)readDataWithTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag; + +/** + * Reads the given number of bytes. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If the length is 0, this method does nothing and the delegate is not called. +**/ +- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads the given number of bytes. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If the length is 0, this method does nothing and the delegate is not called. + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing, and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. +**/ +- (void)readDataToLength:(NSUInteger)length + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If you pass nil or zero-length data as the "data" parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * + * If the timeout value is negative, the read operation will not use a timeout. + * + * If maxLength is zero, no length restriction is enforced. + * Otherwise if maxLength bytes are read without completing the read, + * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError. + * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. + * + * If you pass nil or zero-length data as the "data" parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * If you pass a maxLength parameter that is less than the length of the data parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag; + +/** + * Reads bytes until (and including) the passed "data" parameter, which acts as a separator. + * The bytes will be appended to the given byte buffer starting at the given offset. + * The given buffer will automatically be increased in size if needed. + * + * If the timeout value is negative, the read operation will not use a timeout. + * If the buffer if nil, a buffer will automatically be created for you. + * + * If maxLength is zero, no length restriction is enforced. + * Otherwise if maxLength bytes are read without completing the read, + * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError. + * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end. + * + * If you pass a maxLength parameter that is less than the length of the data (separator) parameter, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * If the bufferOffset is greater than the length of the given buffer, + * the method will do nothing (except maybe print a warning), and the delegate will not be called. + * + * If you pass a buffer, you must not alter it in any way while the socket is using it. + * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer. + * That is, it will reference the bytes that were appended to the given buffer via + * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO]. + * + * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the "data" parameter. + * If you're developing your own custom protocol, be sure your separator can not occur naturally as + * part of the data between separators. + * For example, imagine you want to send several small documents over a socket. + * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents. + * In this particular example, it would be better to use a protocol similar to HTTP with + * a header that includes the length of the document. + * Also be careful that your separator cannot occur naturally as part of the encoding for a character. + * + * The given data (separator) parameter should be immutable. + * For performance reasons, the socket will retain it, not copy it. + * So if it is immutable, don't modify it while the socket is using it. +**/ +- (void)readDataToData:(NSData *)data + withTimeout:(NSTimeInterval)timeout + buffer:(NSMutableData *)buffer + bufferOffset:(NSUInteger)offset + maxLength:(NSUInteger)length + tag:(long)tag; + +/** + * Returns progress of the current read, from 0.0 to 1.0, or NaN if no current read (use isnan() to check). + * The parameters "tag", "done" and "total" will be filled in if they aren't NULL. +**/ +- (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr; + +#pragma mark Writing + +/** + * Writes data to the socket, and calls the delegate when finished. + * + * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called. + * If the timeout value is negative, the write operation will not use a timeout. + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is writing it. In other words, it's not safe to alter the data until after the delegate method + * socket:didWriteDataWithTag: is invoked signifying that this particular write operation has completed. + * This is due to the fact that GCDAsyncSocket does NOT copy the data. It simply retains it. + * This is for performance reasons. Often times, if NSMutableData is passed, it is because + * a request/response was built up in memory. Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes writing the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Returns progress of the current write, from 0.0 to 1.0, or NaN if no current write (use isnan() to check). + * The parameters "tag", "done" and "total" will be filled in if they aren't NULL. +**/ +- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr; + +#pragma mark Security + +/** + * Secures the connection using SSL/TLS. + * + * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes + * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing + * the upgrade to TLS at the same time, without having to wait for the write to finish. + * Any reads or writes scheduled after this method is called will occur over the secured connection. + * + * ==== The available TOP-LEVEL KEYS are: + * + * - GCDAsyncSocketManuallyEvaluateTrust + * The value must be of type NSNumber, encapsulating a BOOL value. + * If you set this to YES, then the underlying SecureTransport system will not evaluate the SecTrustRef of the peer. + * Instead it will pause at the moment evaulation would typically occur, + * and allow us to handle the security evaluation however we see fit. + * So GCDAsyncSocket will invoke the delegate method socket:shouldTrustPeer: passing the SecTrustRef. + * + * Note that if you set this option, then all other configuration keys are ignored. + * Evaluation will be completely up to you during the socket:didReceiveTrust:completionHandler: delegate method. + * + * For more information on trust evaluation see: + * Apple's Technical Note TN2232 - HTTPS Server Trust Evaluation + * https://developer.apple.com/library/ios/technotes/tn2232/_index.html + * + * If unspecified, the default value is NO. + * + * - GCDAsyncSocketUseCFStreamForTLS (iOS only) + * The value must be of type NSNumber, encapsulating a BOOL value. + * By default GCDAsyncSocket will use the SecureTransport layer to perform encryption. + * This gives us more control over the security protocol (many more configuration options), + * plus it allows us to optimize things like sys calls and buffer allocation. + * + * However, if you absolutely must, you can instruct GCDAsyncSocket to use the old-fashioned encryption + * technique by going through the CFStream instead. So instead of using SecureTransport, GCDAsyncSocket + * will instead setup a CFRead/CFWriteStream. And then set the kCFStreamPropertySSLSettings property + * (via CFReadStreamSetProperty / CFWriteStreamSetProperty) and will pass the given options to this method. + * + * Thus all the other keys in the given dictionary will be ignored by GCDAsyncSocket, + * and will passed directly CFReadStreamSetProperty / CFWriteStreamSetProperty. + * For more infomation on these keys, please see the documentation for kCFStreamPropertySSLSettings. + * + * If unspecified, the default value is NO. + * + * ==== The available CONFIGURATION KEYS are: + * + * - kCFStreamSSLPeerName + * The value must be of type NSString. + * It should match the name in the X.509 certificate given by the remote party. + * See Apple's documentation for SSLSetPeerDomainName. + * + * - kCFStreamSSLCertificates + * The value must be of type NSArray. + * See Apple's documentation for SSLSetCertificate. + * + * - kCFStreamSSLIsServer + * The value must be of type NSNumber, encapsulationg a BOOL value. + * See Apple's documentation for SSLCreateContext for iOS. + * This is optional for iOS. If not supplied, a NO value is the default. + * This is not needed for Mac OS X, and the value is ignored. + * + * - GCDAsyncSocketSSLPeerID + * The value must be of type NSData. + * You must set this value if you want to use TLS session resumption. + * See Apple's documentation for SSLSetPeerID. + * + * - GCDAsyncSocketSSLProtocolVersionMin + * - GCDAsyncSocketSSLProtocolVersionMax + * The value(s) must be of type NSNumber, encapsulting a SSLProtocol value. + * See Apple's documentation for SSLSetProtocolVersionMin & SSLSetProtocolVersionMax. + * See also the SSLProtocol typedef. + * + * - GCDAsyncSocketSSLSessionOptionFalseStart + * The value must be of type NSNumber, encapsulating a BOOL value. + * See Apple's documentation for kSSLSessionOptionFalseStart. + * + * - GCDAsyncSocketSSLSessionOptionSendOneByteRecord + * The value must be of type NSNumber, encapsulating a BOOL value. + * See Apple's documentation for kSSLSessionOptionSendOneByteRecord. + * + * - GCDAsyncSocketSSLCipherSuites + * The values must be of type NSArray. + * Each item within the array must be a NSNumber, encapsulating + * See Apple's documentation for SSLSetEnabledCiphers. + * See also the SSLCipherSuite typedef. + * + * - GCDAsyncSocketSSLDiffieHellmanParameters (Mac OS X only) + * The value must be of type NSData. + * See Apple's documentation for SSLSetDiffieHellmanParams. + * + * ==== The following UNAVAILABLE KEYS are: (with throw an exception) + * + * - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE) + * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). + * Corresponding deprecated method: SSLSetAllowsAnyRoot + * + * - kCFStreamSSLAllowsExpiredRoots (UNAVAILABLE) + * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). + * Corresponding deprecated method: SSLSetAllowsExpiredRoots + * + * - kCFStreamSSLAllowsExpiredCertificates (UNAVAILABLE) + * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). + * Corresponding deprecated method: SSLSetAllowsExpiredCerts + * + * - kCFStreamSSLValidatesCertificateChain (UNAVAILABLE) + * You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust). + * Corresponding deprecated method: SSLSetEnableCertVerify + * + * - kCFStreamSSLLevel (UNAVAILABLE) + * You MUST use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMin instead. + * Corresponding deprecated method: SSLSetProtocolVersionEnabled + * + * + * Please refer to Apple's documentation for corresponding SSLFunctions. + * + * If you pass in nil or an empty dictionary, the default settings will be used. + * + * IMPORTANT SECURITY NOTE: + * The default settings will check to make sure the remote party's certificate is signed by a + * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired. + * However it will not verify the name on the certificate unless you + * give it a name to verify against via the kCFStreamSSLPeerName key. + * The security implications of this are important to understand. + * Imagine you are attempting to create a secure connection to MySecureServer.com, + * but your socket gets directed to MaliciousServer.com because of a hacked DNS server. + * If you simply use the default settings, and MaliciousServer.com has a valid certificate, + * the default settings will not detect any problems since the certificate is valid. + * To properly secure your connection in this particular scenario you + * should set the kCFStreamSSLPeerName property to "MySecureServer.com". + * + * You can also perform additional validation in socketDidSecure. +**/ +- (void)startTLS:(NSDictionary *)tlsSettings; + +#pragma mark Advanced + +/** + * Traditionally sockets are not closed until the conversation is over. + * However, it is technically possible for the remote enpoint to close its write stream. + * Our socket would then be notified that there is no more data to be read, + * but our socket would still be writeable and the remote endpoint could continue to receive our data. + * + * The argument for this confusing functionality stems from the idea that a client could shut down its + * write stream after sending a request to the server, thus notifying the server there are to be no further requests. + * In practice, however, this technique did little to help server developers. + * + * To make matters worse, from a TCP perspective there is no way to tell the difference from a read stream close + * and a full socket close. They both result in the TCP stack receiving a FIN packet. The only way to tell + * is by continuing to write to the socket. If it was only a read stream close, then writes will continue to work. + * Otherwise an error will be occur shortly (when the remote end sends us a RST packet). + * + * In addition to the technical challenges and confusion, many high level socket/stream API's provide + * no support for dealing with the problem. If the read stream is closed, the API immediately declares the + * socket to be closed, and shuts down the write stream as well. In fact, this is what Apple's CFStream API does. + * It might sound like poor design at first, but in fact it simplifies development. + * + * The vast majority of the time if the read stream is closed it's because the remote endpoint closed its socket. + * Thus it actually makes sense to close the socket at this point. + * And in fact this is what most networking developers want and expect to happen. + * However, if you are writing a server that interacts with a plethora of clients, + * you might encounter a client that uses the discouraged technique of shutting down its write stream. + * If this is the case, you can set this property to NO, + * and make use of the socketDidCloseReadStream delegate method. + * + * The default value is YES. +**/ +@property (atomic, assign, readwrite) BOOL autoDisconnectOnClosedReadStream; + +/** + * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue. + * In most cases, the instance creates this queue itself. + * However, to allow for maximum flexibility, the internal queue may be passed in the init method. + * This allows for some advanced options such as controlling socket priority via target queues. + * However, when one begins to use target queues like this, they open the door to some specific deadlock issues. + * + * For example, imagine there are 2 queues: + * dispatch_queue_t socketQueue; + * dispatch_queue_t socketTargetQueue; + * + * If you do this (pseudo-code): + * socketQueue.targetQueue = socketTargetQueue; + * + * Then all socketQueue operations will actually get run on the given socketTargetQueue. + * This is fine and works great in most situations. + * But if you run code directly from within the socketTargetQueue that accesses the socket, + * you could potentially get deadlock. Imagine the following code: + * + * - (BOOL)socketHasSomething + * { + * __block BOOL result = NO; + * dispatch_block_t block = ^{ + * result = [self someInternalMethodToBeRunOnlyOnSocketQueue]; + * } + * if (is_executing_on_queue(socketQueue)) + * block(); + * else + * dispatch_sync(socketQueue, block); + * + * return result; + * } + * + * What happens if you call this method from the socketTargetQueue? The result is deadlock. + * This is because the GCD API offers no mechanism to discover a queue's targetQueue. + * Thus we have no idea if our socketQueue is configured with a targetQueue. + * If we had this information, we could easily avoid deadlock. + * But, since these API's are missing or unfeasible, you'll have to explicitly set it. + * + * IF you pass a socketQueue via the init method, + * AND you've configured the passed socketQueue with a targetQueue, + * THEN you should pass the end queue in the target hierarchy. + * + * For example, consider the following queue hierarchy: + * socketQueue -> ipQueue -> moduleQueue + * + * This example demonstrates priority shaping within some server. + * All incoming client connections from the same IP address are executed on the same target queue. + * And all connections for a particular module are executed on the same target queue. + * Thus, the priority of all networking for the entire module can be changed on the fly. + * Additionally, networking traffic from a single IP cannot monopolize the module. + * + * Here's how you would accomplish something like that: + * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock + * { + * dispatch_queue_t socketQueue = dispatch_queue_create("", NULL); + * dispatch_queue_t ipQueue = [self ipQueueForAddress:address]; + * + * dispatch_set_target_queue(socketQueue, ipQueue); + * dispatch_set_target_queue(iqQueue, moduleQueue); + * + * return socketQueue; + * } + * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket + * { + * [clientConnections addObject:newSocket]; + * [newSocket markSocketQueueTargetQueue:moduleQueue]; + * } + * + * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue. + * This is often NOT the case, as such queues are used solely for execution shaping. +**/ +- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue; +- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue; + +/** + * It's not thread-safe to access certain variables from outside the socket's internal queue. + * + * For example, the socket file descriptor. + * File descriptors are simply integers which reference an index in the per-process file table. + * However, when one requests a new file descriptor (by opening a file or socket), + * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor. + * So if we're not careful, the following could be possible: + * + * - Thread A invokes a method which returns the socket's file descriptor. + * - The socket is closed via the socket's internal queue on thread B. + * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD. + * - Thread A is now accessing/altering the file instead of the socket. + * + * In addition to this, other variables are not actually objects, + * and thus cannot be retained/released or even autoreleased. + * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct. + * + * Although there are internal variables that make it difficult to maintain thread-safety, + * it is important to provide access to these variables + * to ensure this class can be used in a wide array of environments. + * This method helps to accomplish this by invoking the current block on the socket's internal queue. + * The methods below can be invoked from within the block to access + * those generally thread-unsafe internal variables in a thread-safe manner. + * The given block will be invoked synchronously on the socket's internal queue. + * + * If you save references to any protected variables and use them outside the block, you do so at your own peril. +**/ +- (void)performBlock:(dispatch_block_t)block; + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's file descriptor(s). + * If the socket is a server socket (is accepting incoming connections), + * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6. +**/ +- (int)socketFD; +- (int)socket4FD; +- (int)socket6FD; + +#if TARGET_OS_IPHONE + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's internal CFReadStream/CFWriteStream. + * + * These streams are only used as workarounds for specific iOS shortcomings: + * + * - Apple has decided to keep the SecureTransport framework private is iOS. + * This means the only supplied way to do SSL/TLS is via CFStream or some other API layered on top of it. + * Thus, in order to provide SSL/TLS support on iOS we are forced to rely on CFStream, + * instead of the preferred and faster and more powerful SecureTransport. + * + * - If a socket doesn't have backgrounding enabled, and that socket is closed while the app is backgrounded, + * Apple only bothers to notify us via the CFStream API. + * The faster and more powerful GCD API isn't notified properly in this case. + * + * See also: (BOOL)enableBackgroundingOnSocket +**/ +- (CFReadStreamRef)readStream; +- (CFWriteStreamRef)writeStream; + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Configures the socket to allow it to operate when the iOS application has been backgrounded. + * In other words, this method creates a read & write stream, and invokes: + * + * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * + * Returns YES if successful, NO otherwise. + * + * Note: Apple does not officially support backgrounding server sockets. + * That is, if your socket is accepting incoming connections, Apple does not officially support + * allowing iOS applications to accept incoming connections while an app is backgrounded. + * + * Example usage: + * + * - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port + * { + * [asyncSocket performBlock:^{ + * [asyncSocket enableBackgroundingOnSocket]; + * }]; + * } +**/ +- (BOOL)enableBackgroundingOnSocket; + +#endif + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's SSLContext, if SSL/TLS has been started on the socket. +**/ +- (SSLContextRef)sslContext; + +#pragma mark Utilities + +/** + * The address lookup utility used by the class. + * This method is synchronous, so it's recommended you use it on a background thread/queue. + * + * The special strings "localhost" and "loopback" return the loopback address for IPv4 and IPv6. + * + * @returns + * A mutable array with all IPv4 and IPv6 addresses returned by getaddrinfo. + * The addresses are specifically for TCP connections. + * You can filter the addresses, if needed, using the other utility methods provided by the class. +**/ ++ (NSMutableArray *)lookupHost:(NSString *)host port:(uint16_t)port error:(NSError **)errPtr; + +/** + * Extracting host and port information from raw address data. +**/ + ++ (NSString *)hostFromAddress:(NSData *)address; ++ (uint16_t)portFromAddress:(NSData *)address; + ++ (BOOL)isIPv4Address:(NSData *)address; ++ (BOOL)isIPv6Address:(NSData *)address; + ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address; + ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(sa_family_t *)afPtr fromAddress:(NSData *)address; + +/** + * A few common line separators, for use with the readDataToData:... methods. +**/ ++ (NSData *)CRLFData; // 0x0D0A ++ (NSData *)CRData; // 0x0D ++ (NSData *)LFData; // 0x0A ++ (NSData *)ZeroData; // 0x00 + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol GCDAsyncSocketDelegate +@optional + +/** + * This method is called immediately prior to socket:didAcceptNewSocket:. + * It optionally allows a listening socket to specify the socketQueue for a new accepted socket. + * If this method is not implemented, or returns NULL, the new accepted socket will create its own default queue. + * + * Since you cannot autorelease a dispatch_queue, + * this method uses the "new" prefix in its name to specify that the returned queue has been retained. + * + * Thus you could do something like this in the implementation: + * return dispatch_queue_create("MyQueue", NULL); + * + * If you are placing multiple sockets on the same queue, + * then care should be taken to increment the retain count each time this method is invoked. + * + * For example, your implementation might look something like this: + * dispatch_retain(myExistingQueue); + * return myExistingQueue; +**/ +- (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock; + +/** + * Called when a socket accepts a connection. + * Another socket is automatically spawned to handle it. + * + * You must retain the newSocket if you wish to handle the connection. + * Otherwise the newSocket instance will be released and the spawned connection will be closed. + * + * By default the new socket will have the same delegate and delegateQueue. + * You may, of course, change this at any time. +**/ +- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket; + +/** + * Called when a socket connects and is ready for reading and writing. + * The host parameter will be an IP address, not a DNS name. +**/ +- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port; + +/** + * Called when a socket has completed reading the requested data into memory. + * Not called if there is an error. +**/ +- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag; + +/** + * Called when a socket has read in data, but has not yet completed the read. + * This would occur if using readToData: or readToLength: methods. + * It may be used to for things such as updating progress bars. +**/ +- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; + +/** + * Called when a socket has completed writing the requested data. Not called if there is an error. +**/ +- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag; + +/** + * Called when a socket has written some data, but has not yet completed the entire write. + * It may be used to for things such as updating progress bars. +**/ +- (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; + +/** + * Called if a read operation has reached its timeout without completing. + * This method allows you to optionally extend the timeout. + * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount. + * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual. + * + * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. + * The length parameter is the number of bytes that have been read so far for the read operation. + * + * Note that this method may be called multiple times for a single read if you return positive numbers. +**/ +- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; + +/** + * Called if a write operation has reached its timeout without completing. + * This method allows you to optionally extend the timeout. + * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount. + * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual. + * + * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method. + * The length parameter is the number of bytes that have been written so far for the write operation. + * + * Note that this method may be called multiple times for a single write if you return positive numbers. +**/ +- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag + elapsed:(NSTimeInterval)elapsed + bytesDone:(NSUInteger)length; + +/** + * Conditionally called if the read stream closes, but the write stream may still be writeable. + * + * This delegate method is only called if autoDisconnectOnClosedReadStream has been set to NO. + * See the discussion on the autoDisconnectOnClosedReadStream method for more information. +**/ +- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock; + +/** + * Called when a socket disconnects with or without error. + * + * If you call the disconnect method, and the socket wasn't already disconnected, + * then an invocation of this delegate method will be enqueued on the delegateQueue + * before the disconnect method returns. + * + * Note: If the GCDAsyncSocket instance is deallocated while it is still connected, + * and the delegate is not also deallocated, then this method will be invoked, + * but the sock parameter will be nil. (It must necessarily be nil since it is no longer available.) + * This is a generally rare, but is possible if one writes code like this: + * + * asyncSocket = nil; // I'm implicitly disconnecting the socket + * + * In this case it may preferrable to nil the delegate beforehand, like this: + * + * asyncSocket.delegate = nil; // Don't invoke my delegate method + * asyncSocket = nil; // I'm implicitly disconnecting the socket + * + * Of course, this depends on how your state machine is configured. +**/ +- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err; + +/** + * Called after the socket has successfully completed SSL/TLS negotiation. + * This method is not called unless you use the provided startTLS method. + * + * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close, + * and the socketDidDisconnect:withError: delegate method will be called with the specific SSL error code. +**/ +- (void)socketDidSecure:(GCDAsyncSocket *)sock; + +/** + * Allows a socket delegate to hook into the TLS handshake and manually validate the peer it's connecting to. + * + * This is only called if startTLS is invoked with options that include: + * - GCDAsyncSocketManuallyEvaluateTrust == YES + * + * Typically the delegate will use SecTrustEvaluate (and related functions) to properly validate the peer. + * + * Note from Apple's documentation: + * Because [SecTrustEvaluate] might look on the network for certificates in the certificate chain, + * [it] might block while attempting network access. You should never call it from your main thread; + * call it only from within a function running on a dispatch queue or on a separate thread. + * + * Thus this method uses a completionHandler block rather than a normal return value. + * The completionHandler block is thread-safe, and may be invoked from a background queue/thread. + * It is safe to invoke the completionHandler block even if the socket has been closed. +**/ +- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust + completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler; + +@end diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/GCDAsyncUdpSocket.h b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/GCDAsyncUdpSocket.h new file mode 100644 index 0000000..7587965 --- /dev/null +++ b/JCPrinterSDK/CocoaAsyncSocket.framework/Headers/GCDAsyncUdpSocket.h @@ -0,0 +1,1007 @@ +// +// GCDAsyncUdpSocket +// +// This class is in the public domain. +// Originally created by Robbie Hanson of Deusty LLC. +// Updated and maintained by Deusty LLC and the Apple development community. +// +// https://github.com/robbiehanson/CocoaAsyncSocket +// + +#import +#import +#import +#import + +extern NSString *const GCDAsyncUdpSocketException; +extern NSString *const GCDAsyncUdpSocketErrorDomain; + +extern NSString *const GCDAsyncUdpSocketQueueName; +extern NSString *const GCDAsyncUdpSocketThreadName; + +typedef NS_ENUM(NSInteger, GCDAsyncUdpSocketError) { + GCDAsyncUdpSocketNoError = 0, // Never used + GCDAsyncUdpSocketBadConfigError, // Invalid configuration + GCDAsyncUdpSocketBadParamError, // Invalid parameter was passed + GCDAsyncUdpSocketSendTimeoutError, // A send operation timed out + GCDAsyncUdpSocketClosedError, // The socket was closed + GCDAsyncUdpSocketOtherError, // Description provided in userInfo +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@class GCDAsyncUdpSocket; + +@protocol GCDAsyncUdpSocketDelegate +@optional + +/** + * By design, UDP is a connectionless protocol, and connecting is not needed. + * However, you may optionally choose to connect to a particular host for reasons + * outlined in the documentation for the various connect methods listed above. + * + * This method is called if one of the connect methods are invoked, and the connection is successful. +**/ +- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address; + +/** + * By design, UDP is a connectionless protocol, and connecting is not needed. + * However, you may optionally choose to connect to a particular host for reasons + * outlined in the documentation for the various connect methods listed above. + * + * This method is called if one of the connect methods are invoked, and the connection fails. + * This may happen, for example, if a domain name is given for the host and the domain name is unable to be resolved. +**/ +- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error; + +/** + * Called when the datagram with the given tag has been sent. +**/ +- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag; + +/** + * Called if an error occurs while trying to send a datagram. + * This could be due to a timeout, or something more serious such as the data being too large to fit in a sigle packet. +**/ +- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error; + +/** + * Called when the socket has received the requested datagram. +**/ +- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data + fromAddress:(NSData *)address + withFilterContext:(id)filterContext; + +/** + * Called when the socket is closed. +**/ +- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error; + +@end + +/** + * You may optionally set a receive filter for the socket. + * A filter can provide several useful features: + * + * 1. Many times udp packets need to be parsed. + * Since the filter can run in its own independent queue, you can parallelize this parsing quite easily. + * The end result is a parallel socket io, datagram parsing, and packet processing. + * + * 2. Many times udp packets are discarded because they are duplicate/unneeded/unsolicited. + * The filter can prevent such packets from arriving at the delegate. + * And because the filter can run in its own independent queue, this doesn't slow down the delegate. + * + * - Since the udp protocol does not guarantee delivery, udp packets may be lost. + * Many protocols built atop udp thus provide various resend/re-request algorithms. + * This sometimes results in duplicate packets arriving. + * A filter may allow you to architect the duplicate detection code to run in parallel to normal processing. + * + * - Since the udp socket may be connectionless, its possible for unsolicited packets to arrive. + * Such packets need to be ignored. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * @param data - The packet that was received. + * @param address - The address the data was received from. + * See utilities section for methods to extract info from address. + * @param context - Out parameter you may optionally set, which will then be passed to the delegate method. + * For example, filter block can parse the data and then, + * pass the parsed data to the delegate. + * + * @returns - YES if the received packet should be passed onto the delegate. + * NO if the received packet should be discarded, and not reported to the delegete. + * + * Example: + * + * GCDAsyncUdpSocketReceiveFilterBlock filter = ^BOOL (NSData *data, NSData *address, id *context) { + * + * MyProtocolMessage *msg = [MyProtocol parseMessage:data]; + * + * *context = response; + * return (response != nil); + * }; + * [udpSocket setReceiveFilter:filter withQueue:myParsingQueue]; + * +**/ +typedef BOOL (^GCDAsyncUdpSocketReceiveFilterBlock)(NSData *data, NSData *address, id *context); + +/** + * You may optionally set a send filter for the socket. + * A filter can provide several interesting possibilities: + * + * 1. Optional caching of resolved addresses for domain names. + * The cache could later be consulted, resulting in fewer system calls to getaddrinfo. + * + * 2. Reusable modules of code for bandwidth monitoring. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * @param data - The packet that was received. + * @param address - The address the data was received from. + * See utilities section for methods to extract info from address. + * @param tag - The tag that was passed in the send method. + * + * @returns - YES if the packet should actually be sent over the socket. + * NO if the packet should be silently dropped (not sent over the socket). + * + * Regardless of the return value, the delegate will be informed that the packet was successfully sent. + * +**/ +typedef BOOL (^GCDAsyncUdpSocketSendFilterBlock)(NSData *data, NSData *address, long tag); + + +@interface GCDAsyncUdpSocket : NSObject + +/** + * GCDAsyncUdpSocket uses the standard delegate paradigm, + * but executes all delegate callbacks on a given delegate dispatch queue. + * This allows for maximum concurrency, while at the same time providing easy thread safety. + * + * You MUST set a delegate AND delegate dispatch queue before attempting to + * use the socket, or you will get an error. + * + * The socket queue is optional. + * If you pass NULL, GCDAsyncSocket will automatically create its own socket queue. + * If you choose to provide a socket queue, the socket queue must not be a concurrent queue, + * then please see the discussion for the method markSocketQueueTargetQueue. + * + * The delegate queue and socket queue can optionally be the same. +**/ +- (id)init; +- (id)initWithSocketQueue:(dispatch_queue_t)sq; +- (id)initWithDelegate:(id )aDelegate delegateQueue:(dispatch_queue_t)dq; +- (id)initWithDelegate:(id )aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq; + +#pragma mark Configuration + +- (id )delegate; +- (void)setDelegate:(id )delegate; +- (void)synchronouslySetDelegate:(id )delegate; + +- (dispatch_queue_t)delegateQueue; +- (void)setDelegateQueue:(dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)delegateQueue; + +- (void)getDelegate:(id *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr; +- (void)setDelegate:(id )delegate delegateQueue:(dispatch_queue_t)delegateQueue; +- (void)synchronouslySetDelegate:(id )delegate delegateQueue:(dispatch_queue_t)delegateQueue; + +/** + * By default, both IPv4 and IPv6 are enabled. + * + * This means GCDAsyncUdpSocket automatically supports both protocols, + * and can send to IPv4 or IPv6 addresses, + * as well as receive over IPv4 and IPv6. + * + * For operations that require DNS resolution, GCDAsyncUdpSocket supports both IPv4 and IPv6. + * If a DNS lookup returns only IPv4 results, GCDAsyncUdpSocket will automatically use IPv4. + * If a DNS lookup returns only IPv6 results, GCDAsyncUdpSocket will automatically use IPv6. + * If a DNS lookup returns both IPv4 and IPv6 results, then the protocol used depends on the configured preference. + * If IPv4 is preferred, then IPv4 is used. + * If IPv6 is preferred, then IPv6 is used. + * If neutral, then the first IP version in the resolved array will be used. + * + * Starting with Mac OS X 10.7 Lion and iOS 5, the default IP preference is neutral. + * On prior systems the default IP preference is IPv4. + **/ +- (BOOL)isIPv4Enabled; +- (void)setIPv4Enabled:(BOOL)flag; + +- (BOOL)isIPv6Enabled; +- (void)setIPv6Enabled:(BOOL)flag; + +- (BOOL)isIPv4Preferred; +- (BOOL)isIPv6Preferred; +- (BOOL)isIPVersionNeutral; + +- (void)setPreferIPv4; +- (void)setPreferIPv6; +- (void)setIPVersionNeutral; + +/** + * Gets/Sets the maximum size of the buffer that will be allocated for receive operations. + * The default maximum size is 9216 bytes. + * + * The theoretical maximum size of any IPv4 UDP packet is UINT16_MAX = 65535. + * The theoretical maximum size of any IPv6 UDP packet is UINT32_MAX = 4294967295. + * + * Since the OS/GCD notifies us of the size of each received UDP packet, + * the actual allocated buffer size for each packet is exact. + * And in practice the size of UDP packets is generally much smaller than the max. + * Indeed most protocols will send and receive packets of only a few bytes, + * or will set a limit on the size of packets to prevent fragmentation in the IP layer. + * + * If you set the buffer size too small, the sockets API in the OS will silently discard + * any extra data, and you will not be notified of the error. +**/ +- (uint16_t)maxReceiveIPv4BufferSize; +- (void)setMaxReceiveIPv4BufferSize:(uint16_t)max; + +- (uint32_t)maxReceiveIPv6BufferSize; +- (void)setMaxReceiveIPv6BufferSize:(uint32_t)max; + +/** + * User data allows you to associate arbitrary information with the socket. + * This data is not used internally in any way. +**/ +- (id)userData; +- (void)setUserData:(id)arbitraryUserData; + +#pragma mark Diagnostics + +/** + * Returns the local address info for the socket. + * + * The localAddress method returns a sockaddr structure wrapped in a NSData object. + * The localHost method returns the human readable IP address as a string. + * + * Note: Address info may not be available until after the socket has been binded, connected + * or until after data has been sent. +**/ +- (NSData *)localAddress; +- (NSString *)localHost; +- (uint16_t)localPort; + +- (NSData *)localAddress_IPv4; +- (NSString *)localHost_IPv4; +- (uint16_t)localPort_IPv4; + +- (NSData *)localAddress_IPv6; +- (NSString *)localHost_IPv6; +- (uint16_t)localPort_IPv6; + +/** + * Returns the remote address info for the socket. + * + * The connectedAddress method returns a sockaddr structure wrapped in a NSData object. + * The connectedHost method returns the human readable IP address as a string. + * + * Note: Since UDP is connectionless by design, connected address info + * will not be available unless the socket is explicitly connected to a remote host/port. + * If the socket is not connected, these methods will return nil / 0. +**/ +- (NSData *)connectedAddress; +- (NSString *)connectedHost; +- (uint16_t)connectedPort; + +/** + * Returns whether or not this socket has been connected to a single host. + * By design, UDP is a connectionless protocol, and connecting is not needed. + * If connected, the socket will only be able to send/receive data to/from the connected host. +**/ +- (BOOL)isConnected; + +/** + * Returns whether or not this socket has been closed. + * The only way a socket can be closed is if you explicitly call one of the close methods. +**/ +- (BOOL)isClosed; + +/** + * Returns whether or not this socket is IPv4. + * + * By default this will be true, unless: + * - IPv4 is disabled (via setIPv4Enabled:) + * - The socket is explicitly bound to an IPv6 address + * - The socket is connected to an IPv6 address +**/ +- (BOOL)isIPv4; + +/** + * Returns whether or not this socket is IPv6. + * + * By default this will be true, unless: + * - IPv6 is disabled (via setIPv6Enabled:) + * - The socket is explicitly bound to an IPv4 address + * _ The socket is connected to an IPv4 address + * + * This method will also return false on platforms that do not support IPv6. + * Note: The iPhone does not currently support IPv6. +**/ +- (BOOL)isIPv6; + +#pragma mark Binding + +/** + * Binds the UDP socket to the given port. + * Binding should be done for server sockets that receive data prior to sending it. + * Client sockets can skip binding, + * as the OS will automatically assign the socket an available port when it starts sending data. + * + * You may optionally pass a port number of zero to immediately bind the socket, + * yet still allow the OS to automatically assign an available port. + * + * You cannot bind a socket after its been connected. + * You can only bind a socket once. + * You can still connect a socket (if desired) after binding. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr. +**/ +- (BOOL)bindToPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * Binds the UDP socket to the given port and optional interface. + * Binding should be done for server sockets that receive data prior to sending it. + * Client sockets can skip binding, + * as the OS will automatically assign the socket an available port when it starts sending data. + * + * You may optionally pass a port number of zero to immediately bind the socket, + * yet still allow the OS to automatically assign an available port. + * + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * You may also use the special strings "localhost" or "loopback" to specify that + * the socket only accept packets from the local machine. + * + * You cannot bind a socket after its been connected. + * You can only bind a socket once. + * You can still connect a socket (if desired) after binding. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr. +**/ +- (BOOL)bindToPort:(uint16_t)port interface:(NSString *)interface error:(NSError **)errPtr; + +/** + * Binds the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * Binding should be done for server sockets that receive data prior to sending it. + * Client sockets can skip binding, + * as the OS will automatically assign the socket an available port when it starts sending data. + * + * You cannot bind a socket after its been connected. + * You can only bind a socket once. + * You can still connect a socket (if desired) after binding. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass NULL for errPtr. +**/ +- (BOOL)bindToAddress:(NSData *)localAddr error:(NSError **)errPtr; + +#pragma mark Connecting + +/** + * Connects the UDP socket to the given host and port. + * By design, UDP is a connectionless protocol, and connecting is not needed. + * + * Choosing to connect to a specific host/port has the following effect: + * - You will only be able to send data to the connected host/port. + * - You will only be able to receive data from the connected host/port. + * - You will receive ICMP messages that come from the connected host/port, such as "connection refused". + * + * The actual process of connecting a UDP socket does not result in any communication on the socket. + * It simply changes the internal state of the socket. + * + * You cannot bind a socket after it has been connected. + * You can only connect a socket once. + * + * The host may be a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). + * + * This method is asynchronous as it requires a DNS lookup to resolve the given host name. + * If an obvious error is detected, this method immediately returns NO and sets errPtr. + * If you don't care about the error, you can pass nil for errPtr. + * Otherwise, this method returns YES and begins the asynchronous connection process. + * The result of the asynchronous connection process will be reported via the delegate methods. + **/ +- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr; + +/** + * Connects the UDP socket to the given address, specified as a sockaddr structure wrapped in a NSData object. + * + * If you have an existing struct sockaddr you can convert it to a NSData object like so: + * struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; + * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; + * + * By design, UDP is a connectionless protocol, and connecting is not needed. + * + * Choosing to connect to a specific address has the following effect: + * - You will only be able to send data to the connected address. + * - You will only be able to receive data from the connected address. + * - You will receive ICMP messages that come from the connected address, such as "connection refused". + * + * Connecting a UDP socket does not result in any communication on the socket. + * It simply changes the internal state of the socket. + * + * You cannot bind a socket after its been connected. + * You can only connect a socket once. + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. + * + * Note: Unlike the connectToHost:onPort:error: method, this method does not require a DNS lookup. + * Thus when this method returns, the connection has either failed or fully completed. + * In other words, this method is synchronous, unlike the asynchronous connectToHost::: method. + * However, for compatibility and simplification of delegate code, if this method returns YES + * then the corresponding delegate method (udpSocket:didConnectToHost:port:) is still invoked. +**/ +- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr; + +#pragma mark Multicast + +/** + * Join multicast group. + * Group should be an IP address (eg @"225.228.0.1"). + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. +**/ +- (BOOL)joinMulticastGroup:(NSString *)group error:(NSError **)errPtr; + +/** + * Join multicast group. + * Group should be an IP address (eg @"225.228.0.1"). + * The interface may be a name (e.g. "en1" or "lo0") or the corresponding IP address (e.g. "192.168.4.35"). + * + * On success, returns YES. + * Otherwise returns NO, and sets errPtr. If you don't care about the error, you can pass nil for errPtr. +**/ +- (BOOL)joinMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr; + +- (BOOL)leaveMulticastGroup:(NSString *)group error:(NSError **)errPtr; +- (BOOL)leaveMulticastGroup:(NSString *)group onInterface:(NSString *)interface error:(NSError **)errPtr; + +#pragma mark Reuse Port + +/** + * By default, only one socket can be bound to a given IP address + port at a time. + * To enable multiple processes to simultaneously bind to the same address+port, + * you need to enable this functionality in the socket. All processes that wish to + * use the address+port simultaneously must all enable reuse port on the socket + * bound to that port. + **/ +- (BOOL)enableReusePort:(BOOL)flag error:(NSError **)errPtr; + +#pragma mark Broadcast + +/** + * By default, the underlying socket in the OS will not allow you to send broadcast messages. + * In order to send broadcast messages, you need to enable this functionality in the socket. + * + * A broadcast is a UDP message to addresses like "192.168.255.255" or "255.255.255.255" that is + * delivered to every host on the network. + * The reason this is generally disabled by default (by the OS) is to prevent + * accidental broadcast messages from flooding the network. +**/ +- (BOOL)enableBroadcast:(BOOL)flag error:(NSError **)errPtr; + +#pragma mark Sending + +/** + * Asynchronously sends the given data, with the given timeout and tag. + * + * This method may only be used with a connected socket. + * Recall that connecting is optional for a UDP socket. + * For connected sockets, data can only be sent to the connected address. + * For non-connected sockets, the remote destination is specified for each packet. + * For more information about optionally connecting udp sockets, see the documentation for the connect methods above. + * + * @param data + * The data to send. + * If data is nil or zero-length, this method does nothing. + * If passing NSMutableData, please read the thread-safety notice below. + * + * @param timeout + * The timeout for the send opeartion. + * If the timeout value is negative, the send operation will not use a timeout. + * + * @param tag + * The tag is for your convenience. + * It is not sent or received over the socket in any manner what-so-ever. + * It is reported back as a parameter in the udpSocket:didSendDataWithTag: + * or udpSocket:didNotSendDataWithTag:dueToError: methods. + * You can use it as an array index, state id, type constant, etc. + * + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method + * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying + * that this particular send operation has completed. + * This is due to the fact that GCDAsyncUdpSocket does NOT copy the data. + * It simply retains it for performance reasons. + * Often times, if NSMutableData is passed, it is because a request/response was built up in memory. + * Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * Asynchronously sends the given data, with the given timeout and tag, to the given host and port. + * + * This method cannot be used with a connected socket. + * Recall that connecting is optional for a UDP socket. + * For connected sockets, data can only be sent to the connected address. + * For non-connected sockets, the remote destination is specified for each packet. + * For more information about optionally connecting udp sockets, see the documentation for the connect methods above. + * + * @param data + * The data to send. + * If data is nil or zero-length, this method does nothing. + * If passing NSMutableData, please read the thread-safety notice below. + * + * @param host + * The destination to send the udp packet to. + * May be specified as a domain name (e.g. "deusty.com") or an IP address string (e.g. "192.168.0.2"). + * You may also use the convenience strings of "loopback" or "localhost". + * + * @param port + * The port of the host to send to. + * + * @param timeout + * The timeout for the send opeartion. + * If the timeout value is negative, the send operation will not use a timeout. + * + * @param tag + * The tag is for your convenience. + * It is not sent or received over the socket in any manner what-so-ever. + * It is reported back as a parameter in the udpSocket:didSendDataWithTag: + * or udpSocket:didNotSendDataWithTag:dueToError: methods. + * You can use it as an array index, state id, type constant, etc. + * + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method + * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying + * that this particular send operation has completed. + * This is due to the fact that GCDAsyncUdpSocket does NOT copy the data. + * It simply retains it for performance reasons. + * Often times, if NSMutableData is passed, it is because a request/response was built up in memory. + * Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)sendData:(NSData *)data + toHost:(NSString *)host + port:(uint16_t)port + withTimeout:(NSTimeInterval)timeout + tag:(long)tag; + +/** + * Asynchronously sends the given data, with the given timeout and tag, to the given address. + * + * This method cannot be used with a connected socket. + * Recall that connecting is optional for a UDP socket. + * For connected sockets, data can only be sent to the connected address. + * For non-connected sockets, the remote destination is specified for each packet. + * For more information about optionally connecting udp sockets, see the documentation for the connect methods above. + * + * @param data + * The data to send. + * If data is nil or zero-length, this method does nothing. + * If passing NSMutableData, please read the thread-safety notice below. + * + * @param remoteAddr + * The address to send the data to (specified as a sockaddr structure wrapped in a NSData object). + * + * @param timeout + * The timeout for the send opeartion. + * If the timeout value is negative, the send operation will not use a timeout. + * + * @param tag + * The tag is for your convenience. + * It is not sent or received over the socket in any manner what-so-ever. + * It is reported back as a parameter in the udpSocket:didSendDataWithTag: + * or udpSocket:didNotSendDataWithTag:dueToError: methods. + * You can use it as an array index, state id, type constant, etc. + * + * + * Thread-Safety Note: + * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while + * the socket is sending it. In other words, it's not safe to alter the data until after the delegate method + * udpSocket:didSendDataWithTag: or udpSocket:didNotSendDataWithTag:dueToError: is invoked signifying + * that this particular send operation has completed. + * This is due to the fact that GCDAsyncUdpSocket does NOT copy the data. + * It simply retains it for performance reasons. + * Often times, if NSMutableData is passed, it is because a request/response was built up in memory. + * Copying this data adds an unwanted/unneeded overhead. + * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket + * completes sending the bytes (which is NOT immediately after this method returns, but rather at a later time + * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method. +**/ +- (void)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag; + +/** + * You may optionally set a send filter for the socket. + * A filter can provide several interesting possibilities: + * + * 1. Optional caching of resolved addresses for domain names. + * The cache could later be consulted, resulting in fewer system calls to getaddrinfo. + * + * 2. Reusable modules of code for bandwidth monitoring. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * For more information about GCDAsyncUdpSocketSendFilterBlock, see the documentation for its typedef. + * To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue. + * + * Note: This method invokes setSendFilter:withQueue:isAsynchronous: (documented below), + * passing YES for the isAsynchronous parameter. +**/ +- (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue; + +/** + * The receive filter can be run via dispatch_async or dispatch_sync. + * Most typical situations call for asynchronous operation. + * + * However, there are a few situations in which synchronous operation is preferred. + * Such is the case when the filter is extremely minimal and fast. + * This is because dispatch_sync is faster than dispatch_async. + * + * If you choose synchronous operation, be aware of possible deadlock conditions. + * Since the socket queue is executing your block via dispatch_sync, + * then you cannot perform any tasks which may invoke dispatch_sync on the socket queue. + * For example, you can't query properties on the socket. +**/ +- (void)setSendFilter:(GCDAsyncUdpSocketSendFilterBlock)filterBlock + withQueue:(dispatch_queue_t)filterQueue + isAsynchronous:(BOOL)isAsynchronous; + +#pragma mark Receiving + +/** + * There are two modes of operation for receiving packets: one-at-a-time & continuous. + * + * In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet. + * Receiving packets one-at-a-time may be better suited for implementing certain state machine code, + * where your state machine may not always be ready to process incoming packets. + * + * In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received. + * Receiving packets continuously is better suited to real-time streaming applications. + * + * You may switch back and forth between one-at-a-time mode and continuous mode. + * If the socket is currently in continuous mode, calling this method will switch it to one-at-a-time mode. + * + * When a packet is received (and not filtered by the optional receive filter), + * the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked. + * + * If the socket is able to begin receiving packets, this method returns YES. + * Otherwise it returns NO, and sets the errPtr with appropriate error information. + * + * An example error: + * You created a udp socket to act as a server, and immediately called receive. + * You forgot to first bind the socket to a port number, and received a error with a message like: + * "Must bind socket before you can receive data." +**/ +- (BOOL)receiveOnce:(NSError **)errPtr; + +/** + * There are two modes of operation for receiving packets: one-at-a-time & continuous. + * + * In one-at-a-time mode, you call receiveOnce everytime your delegate is ready to process an incoming udp packet. + * Receiving packets one-at-a-time may be better suited for implementing certain state machine code, + * where your state machine may not always be ready to process incoming packets. + * + * In continuous mode, the delegate is invoked immediately everytime incoming udp packets are received. + * Receiving packets continuously is better suited to real-time streaming applications. + * + * You may switch back and forth between one-at-a-time mode and continuous mode. + * If the socket is currently in one-at-a-time mode, calling this method will switch it to continuous mode. + * + * For every received packet (not filtered by the optional receive filter), + * the delegate method (udpSocket:didReceiveData:fromAddress:withFilterContext:) is invoked. + * + * If the socket is able to begin receiving packets, this method returns YES. + * Otherwise it returns NO, and sets the errPtr with appropriate error information. + * + * An example error: + * You created a udp socket to act as a server, and immediately called receive. + * You forgot to first bind the socket to a port number, and received a error with a message like: + * "Must bind socket before you can receive data." +**/ +- (BOOL)beginReceiving:(NSError **)errPtr; + +/** + * If the socket is currently receiving (beginReceiving has been called), this method pauses the receiving. + * That is, it won't read any more packets from the underlying OS socket until beginReceiving is called again. + * + * Important Note: + * GCDAsyncUdpSocket may be running in parallel with your code. + * That is, your delegate is likely running on a separate thread/dispatch_queue. + * When you invoke this method, GCDAsyncUdpSocket may have already dispatched delegate methods to be invoked. + * Thus, if those delegate methods have already been dispatch_async'd, + * your didReceive delegate method may still be invoked after this method has been called. + * You should be aware of this, and program defensively. +**/ +- (void)pauseReceiving; + +/** + * You may optionally set a receive filter for the socket. + * This receive filter may be set to run in its own queue (independent of delegate queue). + * + * A filter can provide several useful features. + * + * 1. Many times udp packets need to be parsed. + * Since the filter can run in its own independent queue, you can parallelize this parsing quite easily. + * The end result is a parallel socket io, datagram parsing, and packet processing. + * + * 2. Many times udp packets are discarded because they are duplicate/unneeded/unsolicited. + * The filter can prevent such packets from arriving at the delegate. + * And because the filter can run in its own independent queue, this doesn't slow down the delegate. + * + * - Since the udp protocol does not guarantee delivery, udp packets may be lost. + * Many protocols built atop udp thus provide various resend/re-request algorithms. + * This sometimes results in duplicate packets arriving. + * A filter may allow you to architect the duplicate detection code to run in parallel to normal processing. + * + * - Since the udp socket may be connectionless, its possible for unsolicited packets to arrive. + * Such packets need to be ignored. + * + * 3. Sometimes traffic shapers are needed to simulate real world environments. + * A filter allows you to write custom code to simulate such environments. + * The ability to code this yourself is especially helpful when your simulated environment + * is more complicated than simple traffic shaping (e.g. simulating a cone port restricted router), + * or the system tools to handle this aren't available (e.g. on a mobile device). + * + * Example: + * + * GCDAsyncUdpSocketReceiveFilterBlock filter = ^BOOL (NSData *data, NSData *address, id *context) { + * + * MyProtocolMessage *msg = [MyProtocol parseMessage:data]; + * + * *context = response; + * return (response != nil); + * }; + * [udpSocket setReceiveFilter:filter withQueue:myParsingQueue]; + * + * For more information about GCDAsyncUdpSocketReceiveFilterBlock, see the documentation for its typedef. + * To remove a previously set filter, invoke this method and pass a nil filterBlock and NULL filterQueue. + * + * Note: This method invokes setReceiveFilter:withQueue:isAsynchronous: (documented below), + * passing YES for the isAsynchronous parameter. +**/ +- (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock withQueue:(dispatch_queue_t)filterQueue; + +/** + * The receive filter can be run via dispatch_async or dispatch_sync. + * Most typical situations call for asynchronous operation. + * + * However, there are a few situations in which synchronous operation is preferred. + * Such is the case when the filter is extremely minimal and fast. + * This is because dispatch_sync is faster than dispatch_async. + * + * If you choose synchronous operation, be aware of possible deadlock conditions. + * Since the socket queue is executing your block via dispatch_sync, + * then you cannot perform any tasks which may invoke dispatch_sync on the socket queue. + * For example, you can't query properties on the socket. +**/ +- (void)setReceiveFilter:(GCDAsyncUdpSocketReceiveFilterBlock)filterBlock + withQueue:(dispatch_queue_t)filterQueue + isAsynchronous:(BOOL)isAsynchronous; + +#pragma mark Closing + +/** + * Immediately closes the underlying socket. + * Any pending send operations are discarded. + * + * The GCDAsyncUdpSocket instance may optionally be used again. + * (it will setup/configure/use another unnderlying BSD socket). +**/ +- (void)close; + +/** + * Closes the underlying socket after all pending send operations have been sent. + * + * The GCDAsyncUdpSocket instance may optionally be used again. + * (it will setup/configure/use another unnderlying BSD socket). +**/ +- (void)closeAfterSending; + +#pragma mark Advanced +/** + * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue. + * In most cases, the instance creates this queue itself. + * However, to allow for maximum flexibility, the internal queue may be passed in the init method. + * This allows for some advanced options such as controlling socket priority via target queues. + * However, when one begins to use target queues like this, they open the door to some specific deadlock issues. + * + * For example, imagine there are 2 queues: + * dispatch_queue_t socketQueue; + * dispatch_queue_t socketTargetQueue; + * + * If you do this (pseudo-code): + * socketQueue.targetQueue = socketTargetQueue; + * + * Then all socketQueue operations will actually get run on the given socketTargetQueue. + * This is fine and works great in most situations. + * But if you run code directly from within the socketTargetQueue that accesses the socket, + * you could potentially get deadlock. Imagine the following code: + * + * - (BOOL)socketHasSomething + * { + * __block BOOL result = NO; + * dispatch_block_t block = ^{ + * result = [self someInternalMethodToBeRunOnlyOnSocketQueue]; + * } + * if (is_executing_on_queue(socketQueue)) + * block(); + * else + * dispatch_sync(socketQueue, block); + * + * return result; + * } + * + * What happens if you call this method from the socketTargetQueue? The result is deadlock. + * This is because the GCD API offers no mechanism to discover a queue's targetQueue. + * Thus we have no idea if our socketQueue is configured with a targetQueue. + * If we had this information, we could easily avoid deadlock. + * But, since these API's are missing or unfeasible, you'll have to explicitly set it. + * + * IF you pass a socketQueue via the init method, + * AND you've configured the passed socketQueue with a targetQueue, + * THEN you should pass the end queue in the target hierarchy. + * + * For example, consider the following queue hierarchy: + * socketQueue -> ipQueue -> moduleQueue + * + * This example demonstrates priority shaping within some server. + * All incoming client connections from the same IP address are executed on the same target queue. + * And all connections for a particular module are executed on the same target queue. + * Thus, the priority of all networking for the entire module can be changed on the fly. + * Additionally, networking traffic from a single IP cannot monopolize the module. + * + * Here's how you would accomplish something like that: + * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock + * { + * dispatch_queue_t socketQueue = dispatch_queue_create("", NULL); + * dispatch_queue_t ipQueue = [self ipQueueForAddress:address]; + * + * dispatch_set_target_queue(socketQueue, ipQueue); + * dispatch_set_target_queue(iqQueue, moduleQueue); + * + * return socketQueue; + * } + * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket + * { + * [clientConnections addObject:newSocket]; + * [newSocket markSocketQueueTargetQueue:moduleQueue]; + * } + * + * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue. + * This is often NOT the case, as such queues are used solely for execution shaping. + **/ +- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue; +- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue; + +/** + * It's not thread-safe to access certain variables from outside the socket's internal queue. + * + * For example, the socket file descriptor. + * File descriptors are simply integers which reference an index in the per-process file table. + * However, when one requests a new file descriptor (by opening a file or socket), + * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor. + * So if we're not careful, the following could be possible: + * + * - Thread A invokes a method which returns the socket's file descriptor. + * - The socket is closed via the socket's internal queue on thread B. + * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD. + * - Thread A is now accessing/altering the file instead of the socket. + * + * In addition to this, other variables are not actually objects, + * and thus cannot be retained/released or even autoreleased. + * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct. + * + * Although there are internal variables that make it difficult to maintain thread-safety, + * it is important to provide access to these variables + * to ensure this class can be used in a wide array of environments. + * This method helps to accomplish this by invoking the current block on the socket's internal queue. + * The methods below can be invoked from within the block to access + * those generally thread-unsafe internal variables in a thread-safe manner. + * The given block will be invoked synchronously on the socket's internal queue. + * + * If you save references to any protected variables and use them outside the block, you do so at your own peril. +**/ +- (void)performBlock:(dispatch_block_t)block; + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Provides access to the socket's file descriptor(s). + * If the socket isn't connected, or explicity bound to a particular interface, + * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6. +**/ +- (int)socketFD; +- (int)socket4FD; +- (int)socket6FD; + +#if TARGET_OS_IPHONE + +/** + * These methods are only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Returns (creating if necessary) a CFReadStream/CFWriteStream for the internal socket. + * + * Generally GCDAsyncUdpSocket doesn't use CFStream. (It uses the faster GCD API's.) + * However, if you need one for any reason, + * these methods are a convenient way to get access to a safe instance of one. +**/ +- (CFReadStreamRef)readStream; +- (CFWriteStreamRef)writeStream; + +/** + * This method is only available from within the context of a performBlock: invocation. + * See the documentation for the performBlock: method above. + * + * Configures the socket to allow it to operate when the iOS application has been backgrounded. + * In other words, this method creates a read & write stream, and invokes: + * + * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP); + * + * Returns YES if successful, NO otherwise. + * + * Example usage: + * + * [asyncUdpSocket performBlock:^{ + * [asyncUdpSocket enableBackgroundingOnSocket]; + * }]; + * + * + * NOTE : Apple doesn't currently support backgrounding UDP sockets. (Only TCP for now). +**/ +//- (BOOL)enableBackgroundingOnSockets; + +#endif + +#pragma mark Utilities + +/** + * Extracting host/port/family information from raw address data. +**/ + ++ (NSString *)hostFromAddress:(NSData *)address; ++ (uint16_t)portFromAddress:(NSData *)address; ++ (int)familyFromAddress:(NSData *)address; + ++ (BOOL)isIPv4Address:(NSData *)address; ++ (BOOL)isIPv6Address:(NSData *)address; + ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address; ++ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(int *)afPtr fromAddress:(NSData *)address; + +@end + diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/Info.plist b/JCPrinterSDK/CocoaAsyncSocket.framework/Info.plist new file mode 100644 index 0000000..0459567 Binary files /dev/null and b/JCPrinterSDK/CocoaAsyncSocket.framework/Info.plist differ diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/Modules/module.modulemap b/JCPrinterSDK/CocoaAsyncSocket.framework/Modules/module.modulemap new file mode 100644 index 0000000..6c90f59 --- /dev/null +++ b/JCPrinterSDK/CocoaAsyncSocket.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module CocoaAsyncSocket { + umbrella header "CocoaAsyncSocket.h" + + export * + module * { export * } +} diff --git a/JCPrinterSDK/CocoaAsyncSocket.framework/_CodeSignature/CodeResources b/JCPrinterSDK/CocoaAsyncSocket.framework/_CodeSignature/CodeResources new file mode 100644 index 0000000..0faf204 --- /dev/null +++ b/JCPrinterSDK/CocoaAsyncSocket.framework/_CodeSignature/CodeResources @@ -0,0 +1,201 @@ + + + + + files + + Headers/AsyncSocket.h + + GyStCmhuxAWLghA+fHLwPiSbVNI= + + Headers/AsyncUdpSocket.h + + oqLPl3ROAyiOqTaqhuupNjuxVU0= + + Headers/CocoaAsyncSocket.h + + fwx/DHzHzUQhtlfC9ffKAK+SFx0= + + Headers/GCDAsyncSocket.h + + /7aHrd4SpiKhqk1H7YRnTBSmJow= + + Headers/GCDAsyncUdpSocket.h + + LH5V3wgNYRH1dy/fNu8r4lu8puI= + + Info.plist + + hIIk3iGpMXJkFPisCMWGNsBtuQI= + + Modules/module.modulemap + + +n94rYTWDjekX3imyh+PSyA9vgA= + + + files2 + + Headers/AsyncSocket.h + + hash + + GyStCmhuxAWLghA+fHLwPiSbVNI= + + hash2 + + FK+dN4jyAlPVkpV5Ai//YboXm9aUxPv3x3Q3viDjqTU= + + + Headers/AsyncUdpSocket.h + + hash + + oqLPl3ROAyiOqTaqhuupNjuxVU0= + + hash2 + + aTSbXrHSbcwPrz3/NoP6Q+jWZEwou6OSHQh/8WRkf/0= + + + Headers/CocoaAsyncSocket.h + + hash + + fwx/DHzHzUQhtlfC9ffKAK+SFx0= + + hash2 + + OeCNZd4h1R70nH11jcrFn8m1hnTuvTAHjDhMuhI/3Ao= + + + Headers/GCDAsyncSocket.h + + hash + + /7aHrd4SpiKhqk1H7YRnTBSmJow= + + hash2 + + bOafNUOs6luKovAV0sGzRLmHYf/vKZPF/Wg0IJD1zwQ= + + + Headers/GCDAsyncUdpSocket.h + + hash + + LH5V3wgNYRH1dy/fNu8r4lu8puI= + + hash2 + + CAMdz3VphGMLZyKBHhxLfGK4d70mHUiuHsG45jRPi+0= + + + Modules/module.modulemap + + hash + + +n94rYTWDjekX3imyh+PSyA9vgA= + + hash2 + + RoVn8xMeEnU3Izg0DtYjYL/krI8V7qw0sa7Ggf+08Rs= + + + + rules + + ^ + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^ + + weight + 20 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/JCPrinterSDK/FWnetworkWIFI.h b/JCPrinterSDK/FWnetworkWIFI.h new file mode 100644 index 0000000..a980a07 --- /dev/null +++ b/JCPrinterSDK/FWnetworkWIFI.h @@ -0,0 +1,33 @@ +// +// FWnetworkWIFI.h +// FeasyWifiSDK +// +// Created by wenyewei on 2019/5/30. +// Copyright © 2019年 Feasycom. All rights reserved. +// + +#import +typedef struct Dev +{ + __unsafe_unretained NSString * _Nullable macAddress; + unsigned char type[2]; + unsigned int ip; + __unsafe_unretained NSString * _Nonnull dev_name; +}Dev_Info; +NS_ASSUME_NONNULL_BEGIN +@protocol WIFIManagerDelegate +-(void)didWIFIContect; +-(void)didFindDeviceList:(NSArray *)arr; + +@end +@interface FWnetworkWIFI : NSObject +@property (weak,nonatomic) id delegate; +@property (strong,nonatomic) NSMutableArray *configDeviceList; ++(instancetype)shareManager; +-(BOOL)isEnableWIFI; +-(void)connectWIFIWithSSID:(NSString *)SSID pass:(NSString *)pass; +-(void)startScan; +-(void)stop; +@end + +NS_ASSUME_NONNULL_END diff --git a/JCPrinterSDK/FWnetworkWIFI.mm b/JCPrinterSDK/FWnetworkWIFI.mm new file mode 100644 index 0000000..ee39908 --- /dev/null +++ b/JCPrinterSDK/FWnetworkWIFI.mm @@ -0,0 +1,27 @@ + +#include "FWnetworkWIFI.h" + +@implementation FWnetworkWIFI + ++(instancetype)shareManager{ + FWnetworkWIFI * manager = [super init]; + return manager; +} + +-(BOOL)isEnableWIFI{ + return NO; +} + + +-(void)connectWIFIWithSSID:(NSString *)SSID pass:(NSString *)pass{ + +} +-(void)startScan{ + +} +-(void)stop{ + +} + + +@end diff --git a/JCPrinterSDK/JCAPI.a b/JCPrinterSDK/JCAPI.a new file mode 100644 index 0000000..cac985b Binary files /dev/null and b/JCPrinterSDK/JCAPI.a differ diff --git a/JCPrinterSDK/JCAPI.h b/JCPrinterSDK/JCAPI.h new file mode 100644 index 0000000..f8a0275 --- /dev/null +++ b/JCPrinterSDK/JCAPI.h @@ -0,0 +1,680 @@ +// +// JCAPI.h +// JCPrinterSDK +// +// Created by ydong on 2019/1/29. +// Copyright © 2019 ydong. All rights reserved. +// + +#import +#import + +/** + 建议在iOS9以上系统使用 + */ + + + +typedef NS_ENUM(NSUInteger, JCBarcodeMode){ + //CODEBAR 1D format. + JCBarcodeFormatCodebar , + + //Code 39 1D format. + JCBarcodeFormatCode39 , + + //Code 93 1D format. + JCBarcodeFormatCode93 , + + //Code 128 1D format. + JCBarcodeFormatCode128 , + + //EAN-8 1D format. + JCBarcodeFormatEan8 , + + //EAN-13 1D format. + JCBarcodeFormatEan13 , + + //ITF (Interleaved Two of Five) 1D format. + JCBarcodeFormatITF , + + //UPC-A 1D format. + JCBarcodeFormatUPCA , + + //UPC-E 1D format. + JCBarcodeFormatUPCE +}; + +typedef NS_ENUM(NSUInteger,JCSDKCacheStatus){ + JCSDKCacheWillPrinting, + JCSDKCachePrinting, + JCSDKCacheWillPause, + JCSDKCachePaused, + JCSDKCacheWillCancel, + JCSDKCacheCanceled, + JCSDKCacheWillDone, + JCSDKCacheDone, + JCSDKCacheWillResume, + JCSDKCacheResumed, +} ; + +typedef NS_ENUM(NSUInteger,JCSDKCammodFontType) { + JCSDKCammodFontTypeStandard = 0, + JCSDKCammodFontTypeFreestyleScript, + JCSDKCammodFontTypeOCRA, + JCSDKCammodFontTypeHelveticaNeueLTPro, + JCSDKCammodFontTypeTimesNewRoman, + JCSDKCammodFontTypeMICR, + JCSDKCammodFontTypeTerU24b, + JCSDKCammodFontTypeSimpleChinese16Point = 55, + JCSDKCammodFontTypeSimpleChinese24Point +}; + +typedef NS_ENUM(NSUInteger,JCSDKCammodRotation) { + JCSDKCammodRotationDefault = 0, + JCSDKCammodRotation90 = 90, + JCSDKCammodRotation180 = 180, + JCSDKCammodRotation270 = 270 +}; + +typedef NS_ENUM(NSUInteger,JCSDKCammodGraphicsType) { + JCSDKCammodGraphicsTypeHorizontalExt , + JCSDKCammodGraphicsTypeVerticalExt, + JCSDKCammodGraphicsTypeHorizontalZip, + JCSDKCammodGraphicsTypeVerticalZip +}; + +typedef void (^DidOpened_Printer_Block) (BOOL isSuccess) ; +typedef void (^DidPrinted_Block) (BOOL isSuccess) ; +typedef void (^PRINT_INFO) (NSString * printInfo) ; +typedef void (^PRINT_STATE) (BOOL isSuccess) ; +typedef void (^PRINT_DIC_INFO) (NSDictionary * printDicInfo) ; +typedef void (^JCSDKCACHE_STATE) (JCSDKCacheStatus status) ; + + +@interface JCAPI : NSObject + + +/// @{@"serial":@"V1.0.0",@"date":@"2021/05/06",@"description":@"描述"} ++ (NSDictionary *)version; + + +/// 设置连接的打印机厂商id,需要在连接之前设置 +/// id: 缺省0 ,1-精臣系。 2-B3系。 3-B11系。 4-T2系 +/// @param printerFactoryId 厂商id ++ (void)setPrinterFactoryId:(NSInteger)printerFactoryId; + + +/// 设置第三方接入的对象类名 +/// @param className 类名,必须遵守JC_MyPrinterProtocol协议 ++ (void)setPrinterFactoryTool:(NSString *)className; + + + +/** + 蓝牙/Wi-Fi获取搜索到的打印机列表。 + wifi回调: @[@{@"ipAdd":@"ip地址", @"bleName":@"蓝牙名字"}] + + @param isWifi YES:为搜索Wi-Fi,NO为搜索蓝牙 + @param completion 打印机名字数组block(该名字为连接打印机时的printerName参数) + */ ++ (void)scanPrinterNames:(BOOL)isWifi completion:(void(^)(NSArray *scanedPrinterNames))completion; + + +/** + 蓝牙连接指定名称的打印机。 + + @param printerName 打印机名称。 + @param completion 连接打印机是否成功。(连接状态改变通过该回调返回) + */ ++ (void)openPrinter:(NSString *)printerName + completion:(DidOpened_Printer_Block)completion; + +/** + 打印机类型,连接成功后才能使用,其它厂家打印机返回@“”/@“0”,精臣系打印机返回 + hBit = value/256 + lBit = value%256 + B3S: hBit/lBit = 1 + D11: hBit/lBit = 2 + B21: hBit = 3 + { + L2B: lBit = 1 + L2W: lBit = 2 + C2B: lBit = 3 + C2W: lBit = 4 + C3B: lBit = 5 + C3W: lBit = 6 + } + P1: hBit/lBit = 4 + B16: hBit/lBit = 7 + @return 返回打印机类型 + */ ++(NSInteger )printerTypeInfo; + + +/** + 蓝牙关闭打开的打印机连接。 + */ ++ (void)closePrinter; + + +/** + 蓝牙/Wi-Fi获取当前连接的打印机名称(Wi-Fi为ip地址)。 + + @return 当前连接的打印机名称。 + */ ++ (NSString *)connectingPrinterName; + +/** + 蓝牙/Wi-Fi连接状态 + + @return 2表示连接Wi-Fi,1表示连接蓝牙,0表示无连接 + */ ++ (int)isConnectingState; + +/** + 蓝牙/Wi-Fi设置打印机。 + + @param state 参数为20-30 @param type 对应参数如下 + 21-设置打印浓度 1—淡,2—正常, 3—浓, 4-较浓 5-最浓;(打价器仍只有三挡:1,2,3) + 22-设置打印速度 1—慢, 2—稍慢, 3—正常, 4—稍快, 5—快;(打价器速度三挡) + 23-设置纸张类型 1—间隙纸, 2—黑标纸, 3—连续纸,4-定孔纸,5-透明纸(4,目前还没有) + 24-设置马达驱动(预留) 1 + 25-设置自动出纸(预留) 1、2、3 + 26-设置打印机语言; 1-中文,2-英文 + 27-设置自动关机时间 N分钟 1-4( + 1:15min; + 2:30min; + 3:60min(D11为45分钟); + 4:从不(D11为60分钟) + ) + 28-恢复出厂设置 1 + 29-纸张类型标定 1 + 20-打印模式,限T2支持 1-热敏模式。 2-热感应模式(碳带模式) + 30-音量设置(0-5档) + 31-设置机器防伪 + @param completion 是否设置成功。 + */ ++ (void)setPrintState:(NSInteger)state type:(NSInteger)type sucess:(PRINT_DIC_INFO)completion; + +/** + 蓝牙/Wi-Fi获取打印机信息。b11系列只有9&12 + + @param type 1-打印浓度 + 2-打印速度 + 3-纸张类型 + 4-马达驱动(预留) + 5-自动出纸(预留) + 6-打印机语言 + 7-自动关机时间 + 8-机器型号 + 9-软件版本(固件版本) + 10-当前电量 + 11-机器序列号 + 12-硬件版本 + 13-硬件参数信息(如:电池电压等)----(后面去掉该类型支持) + 14-历史打印信息。 + 15-获取打印机读取成功次数信息(仅支持b21打印机,V2.11支持d11系列3.28以上版本) + 16-查询打印机配网状态(仅支持b21打印机) + 19-获取mac地址 + 20-打印模式(1、热敏 2、热感应) + 21-获取打印机内置地区码 + + @param completion 返回对应的信息。@"UNRESOPN_ERROR"表示获取信息超时 + */ ++ (void)getPrintInfo:(NSInteger)type sucess:(PRINT_DIC_INFO)completion; + +/** + 根据传入参数获取所有的信息 + + @param completion 获取后的回调 + @param arg 参数列表,最大支持10个,必须是+ (void)getPrintInfo:(NSInteger)type sucess:(PRINT_DIC_INFO)completion所支持的type类型,返回结果和传入arg对应的健值对 + */ ++ (void)getInfosWithComplete:(PRINT_DIC_INFO)completion fromArgs:(NSInteger)arg, ...NS_REQUIRES_NIL_TERMINATION; + + +/** + 蓝牙/Wi-Fi是否支持盒盖状态检测 + + @return YES:支持、NO:不支持 + */ ++ (BOOL)isSupportPrintCoverStatus; + +/** + 蓝牙/Wi-Fi盒盖状态改变返回(在连接成功后调用) + + @param completion 盒盖状态:0打开、1关闭 + @param checkPaperBlock 当前打印机是否有耗材:0没有、1有 + @return 是否支持盒盖状态检测:YES:支持、NO:不支持 + */ ++ (BOOL)getPrintCoverStatusChange:(PRINT_INFO)completion withCheckPrinterHavePaperBlock:(PRINT_INFO)checkPaperBlock; + +/** +监听打印机状态变化 + + @param completion + @{ + @"1": 盒盖状态-0打开/1关闭 + @"2": 电量等级变化-1/2/3/4 + @"3": 是否装有纸张-0没有/1有 + @"5": 碳带状态-0无碳带/1有碳带 + } + @return 是否支持监听打印机状态变化:YES:支持、NO:不支持 + */ ++ (BOOL)getPrintStatusChange:(PRINT_DIC_INFO)completion; + +/** + 蓝牙/Wi-Fi是否支持缺纸检测等功能(目前app没有用到具体功能接口,替换为该接口) + + @return 是否支持:YES:支持、NO:不支持 + */ ++ (BOOL)isSupportNOPaper; + +/** + p1打印机打印前传入总打印份数,startDraw:height:orientation:之前调用/startJob之前调用 + + @param totalQuantityOfPrints 总份数 + */ ++ (void)setTotalQuantityOfPrints:(NSInteger)totalQuantityOfPrints; + + + +/** + 蓝牙/Wi-Fi生成带延长线条码最小宽度,单位像素。 + + @param text 条码内容。 + @param barcodeMode 条码类型。 + @param isExtension 是否带延长线:YES为带,NO未不带。 + @return 条码最小宽度。 + */ ++ (NSInteger)getBarCodeWidth:(NSString *)text codeFormat:(JCBarcodeMode)barcodeMode isExtension:(BOOL)isExtension; + +/** + 蓝牙/Wi-Fi生成二维码最小宽度,单位像素。 + + @param text 二维码内容。 + @return 二维码最小宽/高。 + */ ++ (NSInteger)getQRCodeWidth:(NSString *)text; + + +/// 0-正常,1-不支持的类型,2-数据异常,3-长度不符,4-字符不符,5-校验码不符 +/// @param barcodeType 条码类型(20-28) +/// @param content 传入的条码数据 ++ (int)barcodeFormatCheck:(int)barcodeType content:(NSString*)content ; + + +/// 0-正常,1-不支持的类型,2-数据异常,3-长度不符,4-字符不符 +/// @param qrcodeType 条码类型(31-34) +/// @param content 传入的二维码数据 ++ (int)qrcodeFormatCheck:(int)qrcodeType content:(NSString*)content; + +/** + 蓝牙/Wi-Fi返回处理后的条码内容。 + + @param text 条码内容。 + @param barcodeMode 条码类型。 + @return 处理后的条码内容(也可用于检查条码内容是否规范,@"":表示出错) + */ ++ (NSString *)dealBarCodeText:(NSString *)text withBarcodeMode:(JCBarcodeMode)barcodeMode; + +/** + 蓝牙/Wi-Fi获取第几页预览图(在print:之前获取)。 + + @param index 第几页(从0开始) + @return 预览图 + */ ++ (UIImage *)previewImage:(NSInteger)index; + + +/// 打印时获取预览图 ++ (UIImage *)getPrintPreviewImage; + +/** + 蓝牙/Wi-Fi图片直接生成预览图图片。 + + @param image 图像对象。 + @param width 打印对象的尺寸,单位毫米。 + @param height 打印对象的尺寸,单位毫米。 + @param orientation 旋转角度:0:不旋转;90:顺时针旋转90度;180:旋转180度;270:逆时针旋转90度。 + @return 预览图 + */ ++ (UIImage *)drawpreviewImagFromImage:(UIImage *)image + width:(CGFloat)width + height:(CGFloat)height +orientation:(NSInteger)orientation; + + + + +/// 图像二期打印json数据 +/// @param printData json数据 +/// @param printerJson 打印机边距信息 +/// @param onePageNumvers 单页要打印的份数 +/// @param completion 回调 ++ (void)print:(NSString *)printData printAddJson:(NSDictionary *)printerJson withOnePageNumbers:(int)onePageNumvers withComplete:(DidPrinted_Block)completion; + +/** + 蓝牙/Wi-Fi取消打印(打印未完成调用)。 + + @param completion 打印结束回调(在发生异常后不会返回) + */ ++ (void)cancelJob:(DidPrinted_Block)completion; + +/** + 蓝牙/Wi-Fi打印完成(打印完成后调用)。 + + @param completion 打印结束回调(在发生异常后不会返回) + */ ++ (void)endPrint:(DidPrinted_Block)completion; + +/** + 蓝牙/Wi-Fi打价器打印完成的份数(只对打价器有效,可能部分丢失,app做超时重置状态)。 + + @param count 打印完成的份数(在发生异常后不会返回) + @{ + @"totalCount":@"总打印的张数计数" //返回必带的key + @"pageCount":@"当前打印第PageNo页的第几份" //非必带 + @"pageNO":@"当前打印第几页"。 //非必带 + @"tid":@"写入rfid返回的tid码" //非必带 + @"carbonUsed":@"碳带使用量,单位毫米" //非必带 + } + */ ++ (void)getPrintingCountInfo:(PRINT_DIC_INFO)count; + +/** + 蓝牙/Wi-Fi异常接收(连接成功后调用)。 + + @param error 打印异常:1:盒盖打开, + 2:缺纸, + 3:电量不足, + 4:电池异常, + 5:手动停止, + 6:数据错误, + (提交打印数据失败-B3/图像生成失败/发送数据错误,打印机校验不通过打印机返回) + 7:温度过高, + 8:出纸异常, + 9-打印忙碌(当前正在转动马达(正在打印中或者走纸)/打印机正在升级固件) + 10-没有检测到打印头 + 11-环境温度过低 + 12.打印头未锁紧 + 13-未检测到碳带 + 14-不匹配的碳带 + 15-用完的碳带 + 16-不支持的纸张类型 + 17-设置纸张失败 + 18-设置打印模式失败 + 19-设置打印浓度失败(允许打印,仅上报异常) + 20-写入Rfid失败 + 21-边距设置错误 + (边距必须大于0,上边距+下边距必须小于画板高度,左边距+右边距必须小于画板宽度) + 22-通讯异常(超时,打印机指令一直拒绝) + 23-打印机断开 + 24-画板参数设置错误 + 25-旋转角度参数错误 + 26-json参数错误(pc) + 27-出纸异常(关闭上盖检测) + 28-检查纸张类型 + 29-RFID标签进行非RFID模式打印时 + 30-浓度设置不支持 + 31-不支持的打印模式 + 32-标签材质设置失败(材质设置超时或者失败,不阻断正常打印) + 33-不支持的标签材质设置(阻断正常打印) + 34-打印机异常(阻断正常打印) + 35-切刀异常(T2阻断正常打印) + 36-缺纸(T2未放纸) + 37-打印机异常(T2无法通过指令恢复,需要手动按打印机) + */ ++ (void)getPrintingErrorInfo:(PRINT_INFO)error; + +/** + 蓝牙/Wi-Fi像素转毫米(会对像素进行处理)。 + + @param pixel 像素 + @return 绘制参数 + */ ++ (CGFloat)pixelToMm:(CGFloat)pixel; + +/** + 蓝牙/Wi-Fi毫米转像素(会对毫米进行处理)。 + + @param mm 毫米 + @return 绘制参数 + */ ++ (CGFloat)mmToPixel:(CGFloat)mm; + +/** + 蓝牙/Wi-Fi打印机分辨率 + + @return 返回对应的打印机分辨率(连接打印机后有效) + */ ++ (NSInteger)printerResolution; ++ (float)printerMulityDpiToMm; + +/// 设置字体路径 +/// @param fontFamilyPath 路径 ++(void) initImageProcessing:(NSString *) fontFamilyPath error:(NSError **)error; + +/// 准备打印 +/// @param blackRules 设置浓度 +/// @param paperStyle 设置纸张 +/// @param completion 回调 ++ (void)startJob:(int)blackRules + withPaperStyle:(int)paperStyle + withCompletion:(DidPrinted_Block)completion; + + +/// 图像二期毫米转像素 +/// @param mm 毫米 +/// @param scaler 倍率 ++ (int) mmToPixel:(float)mm scaler:(float)scaler; + +/// 图像二期像素转毫米 +/// @param pixel 像素 +/// @param scaler 倍率 ++ (float) pixelToMm:(int)pixel scaler:(float)scaler; + +/// 获取倍率 +/// @param templatePhysical 屏幕物理尺寸 +/// @param screenDisplaySize 屏幕分辨率 ++ (float)getDisplayMultiple:(float)templatePhysical templateDisplayWidth:(int)screenDisplaySize; + + +/// 毫米转英寸 +/// @param mm 毫米 ++(float) mmToInch:(float) mm; + +/// 英寸转毫米 +/// @param inch 英寸 ++(float) inchToMm:(float) inch; + + + + ++(void)didReadSDKCacheStatus:(JCSDKCACHE_STATE)status; + ++(void)setPrintWithCache:(BOOL)startCache; + + +/// 是否支持RFID写入功能 ++(BOOL)isSupportWriteRFID; + + +/// 绘制画板 +/// @param width 宽 +/// @param height 高 +/// @param horizontalShift 水平偏移 +/// @param verticalShift 竖直偏移 +/// @param rotate 旋转角度 +/// @param font 使用字体路径,缺省输入nil ++(void)initDrawingBoard:(float)width + withHeight:(float)height + withHorizontalShift:(float)horizontalShift + withVerticalShift:(float)verticalShift + rotate:(int) rotate + font:(NSString*)font; + + +/// 绘制文本 +/// @param x 水平起点 +/// @param y 竖直起点 +/// @param w 宽 +/// @param h 高 +/// @param text 内容 +/// @param fontFamily 字体 +/// @param fontSize 字体大小 +/// @param rotate 旋转 +/// @param textAlignHorizonral 文本水平对齐方式 0:左对齐 1:居中对齐 2:右对齐 +/// @param textAlignVertical 文本竖直对齐方式 0:顶对齐 1:垂直居中 2:底对齐 +/// @param lineMode 换行方式 +/// @param letterSpacing 字体间隔 +/// @param lineSpacing 行间隔 +/// @param fontStyles [@1,@1,@1,@1] 斜体,加粗,下划线,删除下划线 ++(BOOL)drawLableText:(float)x + withY:(float)y + withWidth:(float)w + withHeight:(float)h + withString:(NSString *)text + withFontFamily:(NSString *)fontFamily + withFontSize:(float)fontSize + withRotate:(int)rotate +withTextAlignHorizonral:(int)textAlignHorizonral +withTextAlignVertical:(int)textAlignVertical + withLineMode:(int)lineMode + withLetterSpacing:(float)letterSpacing + withLineSpacing:(float)lineSpacing + withFontStyle:(NSArray *)fontStyles; + + +/// 绘制条码 +/// @param x 水平坐标 +/// @param y 垂直坐标 +/// @param w 标贴宽度,单位mm +/// @param h 标贴高度,单位mm +/// @param text 文本内容 +/// @param fontSize 文本字号 +/// @param rotate 旋转角度,仅支持0,90,180,270 +/// @param codeType 一维码类型 20:CODE128 21:UPC-A 22:UPC-E 23:EAN8 24:EAN13 25:CODE93 26:CODE39 27:CODEBAR 28:ITF25 +/// @param textHeight 文本高度 +/// @param textPosition 文本位置,int 一维码文字识别码显示位置 0:下方显示 1:上方显示 2:不显示 ++(BOOL)drawLableBarCode:(float)x + withY:(float)y + withWidth:(float)w + withHeight:(float)h + withString:(NSString *)text + withFontSize:(float)fontSize + withRotate:(int)rotate + withCodeType:(int)codeType + withTextHeight:(float)textHeight + withTextPosition:(int)textPosition; + + +/// 绘制二维码 +/// @param x 水平坐标 +/// @param y 垂直坐标 +/// @param w 标贴宽度,单位mm +/// @param h 标贴高度,单位mm +/// @param text 文本内容 +/// @param rotate 旋转角度,仅支持0,90,180,270 +/// @param codeType 二维码类型 31:QR_CODE 32:PDF417 33:DATA_MATRIX 34:AZTEC ++(BOOL)drawLableQrCode:(float)x + withY:(float)y + withWidth:(float)w + withHeight:(float)h + withString:(NSString *)text + withRotate:(int)rotate + withCodeType:(int)codeType; + + +/// 绘制线条 +/// @param x 水平坐标 +/// @param y 垂直坐标 +/// @param w 标贴宽度,单位mm +/// @param h 标贴高度,单位mm +/// @param rotate 旋转角度,仅支持0,90,180,270 +/// @param lineType 线条类型 1:实线 2:虚线类型,虚实比例1:1 +/// @param dashWidth 线条为虚线宽度,【实线段长度,空线段长度】 ++(BOOL)DrawLableLine:(float)x + withY:(float)y + withWidth:(float)w + withHeight:(float)h + withRotate:(int)rotate + withLineType:(int)lineType + withDashWidth:(NSArray *)dashWidth; + + +/// 绘制形状 +/// @param x 水平坐标 +/// @param y 垂直坐标 +/// @param w 标贴宽度,单位mm +/// @param h 标贴高度,单位mm +/// @param lineWidth 线条类型 +/// @param cornerRadius 图像圆角 +/// @param rotate 旋转角度,仅支持0,90,180,270 +/// @param graphType 图形类型 +/// @param lineType 线条类型 1:实线 2:虚线类型,虚实比例1:1 +/// @param dashWidth 线条为虚线宽度,【实线段长度,空线段长度】 ++(BOOL)DrawLableGraph:(float)x + withY:(float)y + withWidth:(float)w + withHeight:(float)h + withLineWidth:(float)lineWidth + withCornerRadius:(float)cornerRadius + withRotate:(int)rotate + withGraphType:(int)graphType + withLineType:(int)lineType + withDashWidth:(NSArray *)dashWidth; + + +/// 绘制图片 +/// @param x 水平坐标 +/// @param y 垂直坐标 +/// @param w 标贴宽度,单位mm +/// @param h 标贴高度,单位mm +/// @param imageData 图像base64数据 +/// @param rotate 旋转角度,仅支持0,90,180,270 +/// @param imageProcessingType 处理算法 +/// @param imageProcessingValue 阈值 ++(BOOL)DrawLableImage:(float)x + withY:(float)y + withWidth:(float)w + withHeight:(float)h + withImageData:(NSString *)imageData + withRotate:(int)rotate +withImageProcessingType:(int)imageProcessingType +withImageProcessingValue:(float)imageProcessingValue; + ++(NSString *)GenerateLableJson; + + +/// 获取预览图 +/// @param displayScale 倍率 +/// @param error 出错返回的错误码 ++(UIImage *)generateImagePreviewImage:(float)displayScale error:(NSError **)error; + + +/// 开始打印 +/// @param printData 打印数据 +/// @param onePageNumvers 打印份数 +/// @param completion 回调 ++ (void)commit:(NSString *)printData +withOnePageNumbers:(int)onePageNumvers + withComplete:(DidPrinted_Block)completion; + + +#pragma mark ###################双色打印################## + +/// 是否是双色打印机,需要连接成功之后调用 ++(int) getPrinterColorType; + + +/// 准备打印 +/// @param blackRules 设置浓度 +/// @param paperStyle 设置纸张 +/// @param completion 回调 ++ (void)startJob:(int)blackRules + withPaperStyle:(int)paperStyle + withColorType:(int)colorType + withCompletion:(DidPrinted_Block)completion; + +@end + diff --git a/JCPrinterSDK/JCPrinterSDK.h b/JCPrinterSDK/JCPrinterSDK.h new file mode 100644 index 0000000..60070cc --- /dev/null +++ b/JCPrinterSDK/JCPrinterSDK.h @@ -0,0 +1,20 @@ +// +// JCPrinterSDK.h +// JCPrinterSDK +// +// Created by 歪脖子 on 2023/10/21. +// + +#import + +//! Project version number for JCPrinterSDK. +FOUNDATION_EXPORT double JCPrinterSDKVersionNumber; + +//! Project version string for JCPrinterSDK. +FOUNDATION_EXPORT const unsigned char JCPrinterSDKVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + +#import +#import diff --git a/JCPrinterSDK/Source/JCSDKPringterConfig.json b/JCPrinterSDK/Source/JCSDKPringterConfig.json new file mode 100644 index 0000000..c742308 --- /dev/null +++ b/JCPrinterSDK/Source/JCSDKPringterConfig.json @@ -0,0 +1,571 @@ +{ + 0:{ + 0:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 1:{ + 0:"printerImageProcessingInfo": { + "name":"B3S", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 2:{ + 0:"printerImageProcessingInfo": { + "name":"D11", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 3:{ + 0:"printerImageProcessingInfo": { + "name":"B21", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 4:{ + 0:"printerImageProcessingInfo": { + "name":"P1S", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 5:{ + 0:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 6:{ + 0:"printerImageProcessingInfo": { + "name":"D11", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 7:{ + 0:"printerImageProcessingInfo": { + "name":"B16", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 8:{ + 0:"printerImageProcessingInfo": { + "name":"B32", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 9:{ + 0:"printerImageProcessingInfo": { + "name":"D110", + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + }, + 10:{ + 0:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 1:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 2:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 3:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 4:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 5:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + 6:"printerImageProcessingInfo": { + "margin": [0, 0, 0, 0], + "imageCrop": [0, 0, 0, 0], + "printMultiple":8, + "horizontalOffset": 0, + "verticalOffset": 0 + }, + } +}