Skip to content

Commit

Permalink
Merge pull request #4 from xremix/develop
Browse files Browse the repository at this point in the history
Code Consistency and updated Docs
  • Loading branch information
xremix authored Jun 28, 2017
2 parents 7f2255b + 811a925 commit 1e24ebd
Show file tree
Hide file tree
Showing 15 changed files with 218 additions and 160 deletions.
42 changes: 25 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A GS1 Barcode Library and Parser written in Swift

This project is mostly a wraper around the complex logic of parsing GS1 Barcode Strings.

## Usage
## Getting started
Parsing is as simple as

```Swift
Expand All @@ -17,11 +17,11 @@ let gs1Barcode = "01101234670417283002\u{1D}1721103110S123456"
let barcode = GS1Barcode(raw: gs1Barcode)

print(barcode.gtin) // 10123467041728
print(barcode.amount) // 2
print(barcode.countOfItems) // 2
print(barcode.expirationDate) // 31.10.2021
print(barcode.lotNumber) // S123456
```
##### Advanced Usage
#### Advanced Usage

To seperate the parsing from initializing I'd recommend a code like

Expand Down Expand Up @@ -66,28 +66,36 @@ print(barcode.applicationIdentifiers["custom1"]!.stringValue)
| productVariant | 20 |
| serialNumber | 21 |
| secondaryDataFields | 22 |
| amount (quantity) | 30 |
| countOfItems | 30 |
| numberOfUnitsContained | 37 |

Other properties can be extended pretty easily. **You** can contribute yourself, or open an [issue](https://github.com/xremix/SwiftGS1Barcode/issues/new) if there is something missing for you.

### Initializers

| Initializer | Description |
| ------------------ |:-------------:|
| `Barcode()` | Creates plain Barcode |
| `Barcode(raw: String)` | Creates Barcode with raw data and parses it |
| `Barcode(raw: String, customApplicationIdentifiers: [String: GS1ApplicationIdentifier])` | Creates Barcode with raw data, custom AIs and parses it |
You can add custom application identifiers by adding them to the key / value dictionary:
```Swift
let barcode = GS1Barcode()
barcode.applicationIdentifiers["custom1"] = GS1ApplicationIdentifier("90", length: 30, type: .String, dynamicLength: true)
```
They'll automatically get parsed by the `parse()` function.
**You can also simply contribute by yourself and add them to the `GS1BarcodeParser.swift` class**, or open an [issue](https://github.com/xremix/SwiftGS1Barcode/issues/new) if there is something missing for you.

## Installation
### CocoaPods
You can install the library to you project using [CocoaPods](https://cocoapods.org). Add the following code to your `Podfile`:
You can install [the library](https://cocoapods.org/pods/SwiftGS1Barcode) to your project by using [CocoaPods](https://cocoapods.org). Add the following code to your `Podfile`:
```
pod 'SwiftGS1Barcode'
platform :ios, '9.0'
use_frameworks!
target 'MyApp' do
pod 'SwiftGS1Barcode'
end
```
Alternative you can also add the direct Github URL:
Alternative you can also add the direct Github source (or a different branch):
```
pod 'SwiftGS1Barcode', :git => 'https://github.com/xremix/SwiftGS1Barcode', :branch => 'master'
platform :ios, '9.0'
use_frameworks!
target 'MyApp' do
pod 'SwiftGS1Barcode', :git => 'https://github.com/xremix/SwiftGS1Barcode', :branch => 'master'
end
```

### Manually
Expand Down
2 changes: 1 addition & 1 deletion SwiftGS1Barcode.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'SwiftGS1Barcode'
s.version = '0.3.3'
s.version = '0.3.4'
s.summary = 'A GS1 Barcode Library and Parser for Swift'

s.description = <<-DESC
Expand Down
12 changes: 6 additions & 6 deletions SwiftGS1Barcode.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
64AE61241F01081800F3B9C0 /* SwiftGS1Barcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 64AE61161F01081800F3B9C0 /* SwiftGS1Barcode.h */; settings = {ATTRIBUTES = (Public, ); }; };
64DD17361F014E1400F10103 /* GS1ApplicationIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DD17351F014E1400F10103 /* GS1ApplicationIdentifier.swift */; };
64DD17381F014F8700F10103 /* GS1ApplicationIdentifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64DD17371F014F8700F10103 /* GS1ApplicationIdentifierTests.swift */; };
E28E99891F01ABC50093C02B /* GS1BarcodeNodeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E28E99881F01ABC50093C02B /* GS1BarcodeNodeTests.swift */; };
E28E99891F01ABC50093C02B /* GS1BarcodeApplicationIdentifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E28E99881F01ABC50093C02B /* GS1BarcodeApplicationIdentifierTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -59,7 +59,7 @@
64AE61231F01081800F3B9C0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
64DD17351F014E1400F10103 /* GS1ApplicationIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GS1ApplicationIdentifier.swift; sourceTree = "<group>"; };
64DD17371F014F8700F10103 /* GS1ApplicationIdentifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GS1ApplicationIdentifierTests.swift; sourceTree = "<group>"; };
E28E99881F01ABC50093C02B /* GS1BarcodeNodeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GS1BarcodeNodeTests.swift; sourceTree = "<group>"; };
E28E99881F01ABC50093C02B /* GS1BarcodeApplicationIdentifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GS1BarcodeApplicationIdentifierTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -123,12 +123,12 @@
64AE61231F01081800F3B9C0 /* Info.plist */,
64754D0B1F01103C00B22B62 /* BarcodeParserTests.swift */,
64754D151F01107B00B22B62 /* DateTests.swift */,
64754D111F01106D00B22B62 /* GS1BarcodeTests.swift */,
64DD17371F014F8700F10103 /* GS1ApplicationIdentifierTests.swift */,
6413187B1F023B0700F9C4DF /* GS1BarcodeAdvancedTests.swift */,
E28E99881F01ABC50093C02B /* GS1BarcodeApplicationIdentifierTests.swift */,
64754D111F01106D00B22B62 /* GS1BarcodeTests.swift */,
64754D0F1F01106500B22B62 /* SimpleBarcodeTests.swift */,
64754D131F01107500B22B62 /* StringTests.swift */,
E28E99881F01ABC50093C02B /* GS1BarcodeNodeTests.swift */,
6413187B1F023B0700F9C4DF /* GS1BarcodeAdvancedTests.swift */,
);
path = SwiftGS1BarcodeTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -264,7 +264,7 @@
64754D161F01107B00B22B62 /* DateTests.swift in Sources */,
64754D141F01107500B22B62 /* StringTests.swift in Sources */,
64754D0C1F01103C00B22B62 /* BarcodeParserTests.swift in Sources */,
E28E99891F01ABC50093C02B /* GS1BarcodeNodeTests.swift in Sources */,
E28E99891F01ABC50093C02B /* GS1BarcodeApplicationIdentifierTests.swift in Sources */,
6413187C1F023B0700F9C4DF /* GS1BarcodeAdvancedTests.swift in Sources */,
64DD17381F014F8700F10103 /* GS1ApplicationIdentifierTests.swift in Sources */,
64754D121F01106D00B22B62 /* GS1BarcodeTests.swift in Sources */,
Expand Down
56 changes: 28 additions & 28 deletions SwiftGS1Barcode/BarcodeParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,58 @@
import UIKit

public class GS1BarcodeParser: NSObject {
static func reduce(data: String?, by node: GS1ApplicationIdentifier)->String?{
static func reduce(data: String?, by ai: GS1ApplicationIdentifier)->String?{
if data == nil{
return data
}

var length = (node.originalValue?.length ?? 0) + (node.identifier.length)
if node.dynamicLength && data!.length > length{
// TODO this should also include the maxlength of the identifier
var length = (ai.originalValue?.length ?? 0) + (ai.identifier.length)
if ai.dynamicLength && data!.length > length{
length += 1
}
return data!.substring(from: length)
}
static func parseGS1ApplicationIdentifier(node: GS1ApplicationIdentifier, data: String)->GS1ApplicationIdentifier{
print("Parsing node with identifier \(node.identifier) of type \(String(describing: node.type?.description))")
static func parseGS1ApplicationIdentifier(_ ai: GS1ApplicationIdentifier, data: String)->GS1ApplicationIdentifier{
print("Parsing application identifier with identifier \(ai.identifier) of type \(String(describing: ai.type?.description))")

if !data.startsWith(node.identifier){
print("Passed invalid Node with wrong node identifier")
return node
if !data.startsWith(ai.identifier){
print("Passed invalid Application Identifier with wrong identifier")
return ai
}

// Get Pure Data by removing the identifier
var nodeData = data
nodeData = nodeData.substring(from: node.identifier.length)
var aiData = data
aiData = aiData.substring(from: ai.identifier.length)


// Cut data by Group Seperator, if dynamic length item and has a GS.
if node.dynamicLength && nodeData.index(of: "\u{1D}") != nil {
let toi = nodeData.index(of: "\u{1D}")
let to = nodeData.distance(from: nodeData.startIndex, to: toi ?? nodeData.startIndex)
if ai.dynamicLength && aiData.index(of: "\u{1D}") != nil {
let toi = aiData.index(of: "\u{1D}")
let to = aiData.distance(from: aiData.startIndex, to: toi ?? aiData.startIndex)

nodeData = nodeData.substring(to: to)
aiData = aiData.substring(to: to)
}
// Cut to Max Length
if nodeData.length > node.maxLength{
nodeData = nodeData.substring(to: node.maxLength)
if aiData.length > ai.maxLength{
aiData = aiData.substring(to: ai.maxLength)
}

// Set original value to the value of the content
node.originalValue = nodeData
ai.originalValue = aiData

// Parsing nodeData, based on the node Type
if node.type == GS1ApplicationIdentifierType.Date && nodeData.length >= 6{ // Parsing 6 Chars to date
// Parsing aiData, based on the ai Type
if ai.type == GS1ApplicationIdentifierType.Date && aiData.length >= 6{ // Parsing 6 Chars to date

node.dateValue = NSDate.from(
year: Int("20" + nodeData.substring(to: 2)),
month: Int(nodeData.substring(2, length: 2)),
day: Int(nodeData.substring(4, length: 2))
ai.dateValue = NSDate.from(
year: Int("20" + aiData.substring(to: 2)),
month: Int(aiData.substring(2, length: 2)),
day: Int(aiData.substring(4, length: 2))
)
}else if(node.type == GS1ApplicationIdentifierType.Int){ // Parsing value to Integer
node.intValue = Int(nodeData)
}else if(ai.type == GS1ApplicationIdentifierType.Numeric){ // Parsing value to Integer
ai.intValue = Int(aiData)
}else{ // Taking the data left and just putting it into the string value
node.stringValue = nodeData
ai.stringValue = aiData
}
return node
return ai
}
}
4 changes: 2 additions & 2 deletions SwiftGS1Barcode/GS1ApplicationIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import UIKit

public enum GS1ApplicationIdentifierType: String{
case Date
case String
case Int
case AlphaNumeric
case Numeric
var description: String{
return self.rawValue
}
Expand Down
48 changes: 24 additions & 24 deletions SwiftGS1Barcode/GS1Barcode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,29 @@ public class GS1Barcode: NSObject, Barcode {

// Dictionary containing all supported application identifiers
public var applicationIdentifiers = [
"serialShippingContainerCode": GS1ApplicationIdentifier("00", length: 18, type: .String),
"gtinOfContainedTradeItems": GS1ApplicationIdentifier("02", length: 14, type: .String),
"gtinIndicatorDigit": GS1ApplicationIdentifier("01", length: 1, type: .Int),
"gtin": GS1ApplicationIdentifier("01", length: 14, type: .String),
"lotNumber": GS1ApplicationIdentifier("10", length: 20, type: .String, dynamicLength: true),
"serialShippingContainerCode": GS1ApplicationIdentifier("00", length: 18, type: .AlphaNumeric),
"gtinOfContainedTradeItems": GS1ApplicationIdentifier("02", length: 14, type: .AlphaNumeric),
"gtin": GS1ApplicationIdentifier("01", length: 14, type: .AlphaNumeric),
"gtinIndicatorDigit": GS1ApplicationIdentifier("01", length: 1, type: .Numeric),
"lotNumber": GS1ApplicationIdentifier("10", length: 20, type: .AlphaNumeric, dynamicLength: true),
"productionDate": GS1ApplicationIdentifier(dateIdentifier: "11"),
"dueDate": GS1ApplicationIdentifier(dateIdentifier: "12"),
"packagingDate": GS1ApplicationIdentifier(dateIdentifier: "13"),
"bestBeforeDate": GS1ApplicationIdentifier(dateIdentifier: "15"),
"expirationDate": GS1ApplicationIdentifier(dateIdentifier: "17"),
"productVariant": GS1ApplicationIdentifier("20", length: 2, type: .String),
"serialNumber": GS1ApplicationIdentifier("21", length: 20, type: .String, dynamicLength: true),
"secondaryDataFields": GS1ApplicationIdentifier("22", length:29, type: .String, dynamicLength:true),
"amount": GS1ApplicationIdentifier("30", length: 8, type: .Int, dynamicLength: true),
"numberOfUnitsContained": GS1ApplicationIdentifier("37", length:8, type: .String, dynamicLength:true),
"productVariant": GS1ApplicationIdentifier("20", length: 2, type: .AlphaNumeric),
"serialNumber": GS1ApplicationIdentifier("21", length: 20, type: .AlphaNumeric, dynamicLength: true),
"secondaryDataFields": GS1ApplicationIdentifier("22", length:29, type: .AlphaNumeric, dynamicLength:true),
"countOfItems": GS1ApplicationIdentifier("30", length: 8, type: .Numeric, dynamicLength: true),
"numberOfUnitsContained": GS1ApplicationIdentifier("37", length:8, type: .AlphaNumeric, dynamicLength:true),
]

// Mapping for User Friendly Usage
public var gtin: String?{ get {return applicationIdentifiers["gtin"]!.stringValue} }
public var lotNumber: String?{ get {return applicationIdentifiers["lotNumber"]!.stringValue} }
public var expirationDate: NSDate?{ get {return applicationIdentifiers["expirationDate"]!.dateValue} }
public var serialNumber: String?{ get {return applicationIdentifiers["serialNumber"]!.stringValue} }
public var amount: Int?{ get {return applicationIdentifiers["amount"]!.intValue} }
public var countOfItems: Int?{ get {return applicationIdentifiers["countOfItems"]!.intValue} }
public var gtinIndicatorDigit: Int? {get {return applicationIdentifiers["gtinIndicatorDigit"]!.intValue}}
// TODO Order could be changed to fit dictionary above
public var serialShippingContainerCode: String? {get{return applicationIdentifiers["serialShippingContainerCode"]!.stringValue}}
Expand Down Expand Up @@ -82,14 +82,14 @@ public class GS1Barcode: NSObject, Barcode {
return lastParseSuccessfull && raw != "" && raw != nil
}

private func parseNode(node: inout GS1ApplicationIdentifier, data: inout String)->Bool{
if(data.startsWith(node.identifier)){
node = GS1BarcodeParser.parseGS1ApplicationIdentifier(node: node, data: data)
// Fixes issue where two nodes have the same identifier
if node.identifier == "01"{
applicationIdentifiers["gtinIndicatorDigit"] = GS1BarcodeParser.parseGS1ApplicationIdentifier(node: applicationIdentifiers["gtinIndicatorDigit"]!, data: data)
private func parseApplicationIdentifier(_ ai: inout GS1ApplicationIdentifier, data: inout String)->Bool{
if(data.startsWith(ai.identifier)){
ai = GS1BarcodeParser.parseGS1ApplicationIdentifier(ai, data: data)
// Fixes issue where two AIs have the same identifier (TODO: should maybe get rid of gtinIndicatorDigit)
if ai.identifier == "01"{
applicationIdentifiers["gtinIndicatorDigit"] = GS1BarcodeParser.parseGS1ApplicationIdentifier(applicationIdentifiers["gtinIndicatorDigit"]!, data: data)
}
data = GS1BarcodeParser.reduce(data: data, by: node)!
data = GS1BarcodeParser.reduce(data: data, by: ai)!

return true
}
Expand All @@ -107,19 +107,19 @@ public class GS1Barcode: NSObject, Barcode {
data = data!.substring(from: 1)
}

// Checking the nodes by it's identifier and passing it to the Barcode Parser to get the value and cut the data
// Checking the AIs by it's identifier and passing it to the Barcode Parser to get the value and cut the data
var foundOne = false
for nodeKey in applicationIdentifiers.keys{
for aiKey in applicationIdentifiers.keys{
// Exclude the gtinIndicatorDigit, because it get's added later for the gtin identifier
if nodeKey != "gtinIndicatorDigit"{
// If could parse node, continue and do the loop once again
if(parseNode(node: &applicationIdentifiers[nodeKey]!, data: &data!)){
if aiKey != "gtinIndicatorDigit"{
// If could parse ai, continue and do the loop once again
if(parseApplicationIdentifier(&applicationIdentifiers[aiKey]!, data: &data!)){
foundOne = true
continue
}
}
}
// If no node was found return false and keep the lastParseSuccessfull to false
// If no ai was found return false and keep the lastParseSuccessfull to false -> This will make validate() fail as well
if !foundOne{
print("Do not know identifier. Canceling Parsing")
return false
Expand Down
2 changes: 1 addition & 1 deletion SwiftGS1Barcode/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.3.3</string>
<string>0.3.4</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
Loading

0 comments on commit 1e24ebd

Please sign in to comment.