TagAdA

source: branches/mac/Sources/Model/TGDFileHash.c

Last change on this file was 228, checked in by Joel Lopes Da Silva, 8 years ago

Fixing comments.

File size: 8.0 KB
Line 
1/*
2 *  TGDFileHash.c
3 *  TagAdA: Tagging Advanced Application
4 * 
5 *  Copyright © 2008-2010 The TagAdA Team. All rights reserved.
6 *
7 *  Licensed under the Apache License, Version 2.0 (the "License");
8 *  you may not use this file except in compliance with the License.
9 *  You may obtain a copy of the License at
10 * 
11 *        http://www.apache.org/licenses/LICENSE-2.0
12 * 
13 *  Unless required by applicable law or agreed to in writing, software
14 *  distributed under the License is distributed on an "AS IS" BASIS,
15 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 *  See the License for the specific language governing permissions and
17 *  limitations under the License.
18 *
19 */
20
21//---------------------------------------------------------
22// Includes
23//---------------------------------------------------------
24
25// Header file
26#include "TGDFileHash.h"
27
28// Standard library
29#include <stdint.h>
30#include <stdio.h>
31
32// Cryptography
33#include <CommonCrypto/CommonDigest.h>
34
35
36//---------------------------------------------------------
37// Other declarations
38//---------------------------------------------------------
39
40#pragma mark -
41#pragma mark Private types definitions
42
43// Function pointer types for functions used in the computation
44// of a cryptographic hash.
45typedef int (*TGDHashInitFunction)   (uint8_t *hashObjectPointer[]);
46typedef int (*TGDHashUpdateFunction) (uint8_t *hashObjectPointer[], 
47                                      const void *data, 
48                                      CC_LONG len);
49typedef int (*TGDHashFinalFunction)  (unsigned char *md, 
50                                      uint8_t *hashObjectPointer[]);
51
52// Structure used to describe a hash computation context.
53typedef struct _TGDHashComputationContext {
54    TGDHashInitFunction initFunction;
55    TGDHashUpdateFunction updateFunction;
56    TGDHashFinalFunction finalFunction;
57    size_t digestLength;
58    uint8_t **hashObjectPointer;
59} TGDHashComputationContext;
60
61
62#pragma mark -
63#pragma mark Private functions declarations
64
65static CFStringRef _TGDFileHashCreateWithPath(CFStringRef filePath, 
66                                              size_t chunkSizeForReadingData, 
67                                              TGDHashComputationContext *context);
68
69
70#pragma mark -
71#pragma mark Handy preprocessor macros
72
73// From <CommonCrypto/CommonDigest.h>:
74//     - same context struct is used for SHA224 and SHA256;
75//     - same context struct is used for SHA384 and SHA512.
76#define CC_SHA224_CTX CC_SHA256_CTX
77#define CC_SHA384_CTX CC_SHA512_CTX
78
79
80// Macro to easily setup a TGDHashComputationContext given
81// a hash algorithm name.
82#define TGDHashComputationContextDeclare(context, hashAlgorithmName)        \
83    CC_##hashAlgorithmName##_CTX hashObjectFor##hashAlgorithmName;          \
84    TGDHashComputationContext context = {                                   \
85        (TGDHashInitFunction)&CC_##hashAlgorithmName##_Init,                \
86        (TGDHashUpdateFunction)&CC_##hashAlgorithmName##_Update,            \
87        (TGDHashFinalFunction)&CC_##hashAlgorithmName##_Final,              \
88        CC_##hashAlgorithmName##_DIGEST_LENGTH,                             \
89        (uint8_t **)&hashObjectFor##hashAlgorithmName                       \
90    }
91
92
93// Macro used in TGDFileHashCreateWithPath to easily add more cases
94// to the switch block with just the hash algorithm name.
95#define TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(                  \
96            hashAlgorithmName                                               \
97        )                                                                   \
98                                                                            \
99        case TGDHashAlgorithm##hashAlgorithmName:                           \
100            do {                                                            \
101                TGDHashComputationContextDeclare(hashComputationContext,    \
102                                                 hashAlgorithmName);        \
103                return _TGDFileHashCreateWithPath(filePath,                 \
104                                                  chunkSizeForReadingData,  \
105                                                  &hashComputationContext); \
106            } while(false)
107
108
109//---------------------------------------------------------
110// Functions definitions
111//---------------------------------------------------------
112
113#pragma mark -
114#pragma mark Functions definitions
115
116CFStringRef TGDFileHashCreateWithPath(CFStringRef filePath, 
117                                      size_t chunkSizeForReadingData, 
118                                      TGDHashAlgorithm hashAlgorithm) {
119   
120    switch (hashAlgorithm) {
121        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(MD2);
122        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(MD4);
123        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(MD5);
124        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(SHA1);
125        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(SHA224);
126        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(SHA256);
127        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(SHA384);
128        TGDFileHashCreateWithPath_CaseHashAlgorithmBranch(SHA512);
129        default:
130            break;
131    }
132    return NULL;
133}
134
135
136static CFStringRef _TGDFileHashCreateWithPath(CFStringRef filePath, 
137                                              size_t chunkSizeForReadingData, 
138                                              TGDHashComputationContext *context) {
139   
140    // Declare needed variables and buffers
141    CFStringRef result = NULL;
142    CFReadStreamRef readStream = NULL;
143    unsigned char digest[context->digestLength];
144    char hash[2 * context->digestLength + 1];
145   
146    // Get the file URL
147    CFURLRef fileURL = 
148        CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 
149                                      (CFStringRef)filePath, 
150                                      kCFURLPOSIXPathStyle, 
151                                      (Boolean)false);
152    if (!fileURL) goto done;
153   
154    // Create and open the read stream
155    readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, 
156                                            (CFURLRef)fileURL);
157    if (!readStream) goto done;
158    bool didSucceed = (bool)CFReadStreamOpen(readStream);
159    if (!didSucceed) goto done;
160   
161    // Initialize the hash object
162    (*context->initFunction)(context->hashObjectPointer);
163   
164    // Make sure chunkSizeForReadingData is valid
165    if (!chunkSizeForReadingData) {
166        chunkSizeForReadingData = TGDFileHashDefaultChunkSizeForReadingData;
167    }
168   
169    // Feed the data to the hash object
170    bool hasMoreData = true;
171    while (hasMoreData) {
172        uint8_t buffer[chunkSizeForReadingData];
173        CFIndex readBytesCount = CFReadStreamRead(readStream, 
174                                                  (UInt8 *)buffer, 
175                                                  (CFIndex)sizeof(buffer));
176        if (readBytesCount == -1) break;
177        if (readBytesCount == 0) {
178            hasMoreData = false;
179            continue;
180        }
181        (*context->updateFunction)(context->hashObjectPointer, 
182                                   (const void *)buffer, 
183                                   (CC_LONG)readBytesCount);
184    }
185   
186    // Check if the read operation succeeded
187    didSucceed = !hasMoreData;
188   
189    // Compute the hash digest
190    (*context->finalFunction)(digest, context->hashObjectPointer);
191   
192    // Abort if the read operation failed
193    if (!didSucceed) goto done;
194   
195    // Compute the string result
196    for (size_t i = 0; i < context->digestLength; ++i) {
197        snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
198    }
199    result = CFStringCreateWithCString(kCFAllocatorDefault, 
200                                       (const char *)hash, 
201                                       kCFStringEncodingUTF8);
202   
203done:
204   
205    if (readStream) {
206        CFReadStreamClose(readStream);
207        CFRelease(readStream);
208    }
209    if (fileURL) {
210        CFRelease(fileURL);
211    }
212    return result;
213   
214}
Note: See TracBrowser for help on using the repository browser.
Copyright © 2008-2017 The TagAdA Team. All rights reserved.