From 8efb424b470288cd7f5cd21fb23e42df043cdd96 Mon Sep 17 00:00:00 2001 From: Alexander Brausch Date: Tue, 3 Jul 2012 15:24:02 +0200 Subject: [PATCH] 'Added loadFromString and tests --- CSSParser.h | 2 +- CSSParser.m | 28 +++++++-- CSSSample.xcodeproj/project.pbxproj | 14 +++++ CSSStyleSheet.m | 13 +++- Tests/CSSStyleSheetTest.h | 16 +++++ Tests/CSSStyleSheetTest.m | 25 ++++++++ fmemopen.c | 92 +++++++++++++++++++++++++++++ fmemopen.h | 43 ++++++++++++++ 8 files changed, 225 insertions(+), 8 deletions(-) create mode 100644 Tests/CSSStyleSheetTest.h create mode 100644 Tests/CSSStyleSheetTest.m create mode 100755 fmemopen.c create mode 100755 fmemopen.h diff --git a/CSSParser.h b/CSSParser.h index 11268df..5338cc7 100644 --- a/CSSParser.h +++ b/CSSParser.h @@ -32,5 +32,5 @@ } - (NSDictionary*)parseFilename:(NSString*)filename; - +- (NSDictionary*)parseString:(NSString*) string; @end diff --git a/CSSParser.m b/CSSParser.m index 5b8b85c..4fe5302 100644 --- a/CSSParser.m +++ b/CSSParser.m @@ -9,6 +9,7 @@ #import "CSSTokens.h" #import "css.h" #import "CSSParser.h" +#import "fmemopen.h" typedef enum { @@ -257,10 +258,7 @@ - (UIColor *) colorWithHexString: (NSString *) stringToConvert #pragma mark - #pragma mark Public - - -- (NSDictionary*)parseFilename:(NSString*)filename -{ +- (void) reset { gActiveParser = self; [_ruleSets removeAllObjects]; @@ -268,6 +266,12 @@ - (NSDictionary*)parseFilename:(NSString*)filename _activeRuleSet=nil; _activePropertyName=nil; _lastTokenText=nil; +} + + +- (NSDictionary*)parseFilename:(NSString*)filename +{ + [self reset]; cssin = fopen([filename UTF8String], "r"); @@ -280,4 +284,20 @@ - (NSDictionary*)parseFilename:(NSString*)filename return result; } +- (NSDictionary *)parseString:(NSString *)string { + [self reset]; + + const char* cstr = [string UTF8String]; + + cssin = fmemopen((void *)cstr, sizeof(char) * (string.length + 1), "r"); + + csslex(); + + fclose(cssin); + + NSDictionary* result = [_ruleSets copy]; + _ruleSets=nil; + return result; +} + @end diff --git a/CSSSample.xcodeproj/project.pbxproj b/CSSSample.xcodeproj/project.pbxproj index 37f3564..6c98861 100644 --- a/CSSSample.xcodeproj/project.pbxproj +++ b/CSSSample.xcodeproj/project.pbxproj @@ -34,6 +34,9 @@ AB588FD113D2442600EC6441 /* GHUnitIOSTestMain.m in Sources */ = {isa = PBXBuildFile; fileRef = AB588F9B13D2427100EC6441 /* GHUnitIOSTestMain.m */; }; AB588FD513D245A700EC6441 /* CSSObjectCategoryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AB588FD413D245A700EC6441 /* CSSObjectCategoryTest.m */; }; AB588FD913D24DB500EC6441 /* CSSViewSelectorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AB588FD813D24DB500EC6441 /* CSSViewSelectorTest.m */; }; + B96A597815A3259E0085D72D /* fmemopen.c in Sources */ = {isa = PBXBuildFile; fileRef = B96A597615A3259E0085D72D /* fmemopen.c */; }; + B96A597A15A325FC0085D72D /* fmemopen.c in Sources */ = {isa = PBXBuildFile; fileRef = B96A597615A3259E0085D72D /* fmemopen.c */; }; + B96A597D15A326F70085D72D /* CSSStyleSheetTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B96A597C15A326F70085D72D /* CSSStyleSheetTest.m */; }; D9141F5C13D26A4A006B25E0 /* css.m in Sources */ = {isa = PBXBuildFile; fileRef = D9141F5A13D26A4A006B25E0 /* css.m */; }; D9141F5D13D26A4A006B25E0 /* mcss.grammer in Resources */ = {isa = PBXBuildFile; fileRef = D9141F5B13D26A4A006B25E0 /* mcss.grammer */; }; D9C27FF313D24CA3000B1A43 /* testcase.css in Resources */ = {isa = PBXBuildFile; fileRef = D9C27FF213D24CA3000B1A43 /* testcase.css */; }; @@ -99,6 +102,10 @@ AB588FD813D24DB500EC6441 /* CSSViewSelectorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSViewSelectorTest.m; sourceTree = ""; }; AB5B475013D2272B00FB2A74 /* UIView+CSS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+CSS.h"; sourceTree = ""; }; AB5B475113D2272B00FB2A74 /* UIView+CSS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+CSS.m"; sourceTree = ""; }; + B96A597615A3259E0085D72D /* fmemopen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmemopen.c; sourceTree = ""; }; + B96A597715A3259E0085D72D /* fmemopen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fmemopen.h; sourceTree = ""; }; + B96A597B15A326F70085D72D /* CSSStyleSheetTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSStyleSheetTest.h; sourceTree = ""; }; + B96A597C15A326F70085D72D /* CSSStyleSheetTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSSStyleSheetTest.m; sourceTree = ""; }; D9141F5913D26A4A006B25E0 /* css.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = css.h; path = lex/css.h; sourceTree = ""; }; D9141F5A13D26A4A006B25E0 /* css.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = css.m; path = lex/css.m; sourceTree = ""; }; D9141F5B13D26A4A006B25E0 /* mcss.grammer */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mcss.grammer; path = lex/mcss.grammer; sourceTree = ""; }; @@ -149,6 +156,8 @@ children = ( 1D91E74413D29F1F009C11F8 /* Selector Tree */, 1DF02A9E13D285D3005A3D0C /* Lex */, + B96A597615A3259E0085D72D /* fmemopen.c */, + B96A597715A3259E0085D72D /* fmemopen.h */, 1DEE03D013D23514007C87FE /* CSSParser.h */, 1DEE03D113D23514007C87FE /* CSSParser.m */, 1DEE03DC13D24349007C87FE /* CSSStyleSheet.h */, @@ -317,6 +326,8 @@ AB588FD413D245A700EC6441 /* CSSObjectCategoryTest.m */, AB588FD713D24DB500EC6441 /* CSSViewSelectorTest.h */, AB588FD813D24DB500EC6441 /* CSSViewSelectorTest.m */, + B96A597B15A326F70085D72D /* CSSStyleSheetTest.h */, + B96A597C15A326F70085D72D /* CSSStyleSheetTest.m */, ); name = "Test Cases"; sourceTree = ""; @@ -428,6 +439,7 @@ AB0ECAE513D25B0A00E151DF /* NSObject+CSS.m in Sources */, 1D7B93D313D28E1B00F4AA31 /* UIView+CSS.m in Sources */, 1D91E74313D29E33009C11F8 /* CSSSelectorTree.m in Sources */, + B96A597815A3259E0085D72D /* fmemopen.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -449,6 +461,8 @@ AB588FD113D2442600EC6441 /* GHUnitIOSTestMain.m in Sources */, AB588FD513D245A700EC6441 /* CSSObjectCategoryTest.m in Sources */, AB588FD913D24DB500EC6441 /* CSSViewSelectorTest.m in Sources */, + B96A597A15A325FC0085D72D /* fmemopen.c in Sources */, + B96A597D15A326F70085D72D /* CSSStyleSheetTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/CSSStyleSheet.m b/CSSStyleSheet.m index 798b5e9..bb4c3cf 100644 --- a/CSSStyleSheet.m +++ b/CSSStyleSheet.m @@ -26,8 +26,9 @@ + (CSSStyleSheet*)styleSheetFromURL:(NSURL *)url + (CSSStyleSheet*)styleSheetFromString:(NSString *)css_code { - //TODO: load and parse from string - return nil; + CSSStyleSheet *sheet = [[CSSStyleSheet alloc] init]; + [sheet loadFromString: css_code]; + return sheet; } - (void)loadFromURL:(NSURL*)url @@ -42,7 +43,13 @@ - (void)loadFromURL:(NSURL*)url } - (void)loadFromString:(NSString *)css_code { - //TODO: load from string (need it in the parser class.) + parser = [[CSSParser alloc] init]; + + // grab the entire file and load the rule dictionary. + NSDictionary *rules = [parser parseString: css_code]; + + //build the tree from the parsed rules + [self buildTree:rules]; } #pragma mark Tree Parsing methods diff --git a/Tests/CSSStyleSheetTest.h b/Tests/CSSStyleSheetTest.h new file mode 100644 index 0000000..432df71 --- /dev/null +++ b/Tests/CSSStyleSheetTest.h @@ -0,0 +1,16 @@ +// +// CSSViewSelectorTest.h +// CSSSample +// +// Created by Alexander Brausch on 03/07/2012. +// Copyright 2012 Alexander Brausch. All rights reserved. +// +#import + +#import + +@interface CSSStyleSheetTest : GHTestCase { +@private +} + +@end diff --git a/Tests/CSSStyleSheetTest.m b/Tests/CSSStyleSheetTest.m new file mode 100644 index 0000000..27290b9 --- /dev/null +++ b/Tests/CSSStyleSheetTest.m @@ -0,0 +1,25 @@ +// +// CSSViewSelectorTest.h +// CSSSample +// +// Created by Alexander Brausch on 03/07/2012. +// Copyright 2012 Alexander Brausch. All rights reserved. +// + + +#import "CSSStyleSheetTest.h" + +#import "CSSStyleSheet.h" +#import "CSSSelector.h" +#import "CSSSelectorTree.h" + +@implementation CSSStyleSheetTest + +- (void) testLoadFromString { + CSSStyleSheet* sheet = [CSSStyleSheet styleSheetFromString: @".foo.bar{background-color:black}"]; + + NSUInteger count = [sheet.root.nodes count]; + GHAssertTrue( count == 1, @"Invalid count %d",count); +} + +@end diff --git a/fmemopen.c b/fmemopen.c new file mode 100755 index 0000000..0fd495d --- /dev/null +++ b/fmemopen.c @@ -0,0 +1,92 @@ +// +// Copyright 2012 Jeff Verkoeyen +// Originally ported from https://github.com/ingenuitas/python-tesseract/blob/master/fmemopen.c +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include +#include +#include +#include + +struct fmem { + size_t pos; + size_t size; + char *buffer; +}; +typedef struct fmem fmem_t; + +static int readfn(void *handler, char *buf, int size) { + fmem_t *mem = handler; + size_t available = mem->size - mem->pos; + + if (size > available) { + size = available; + } + memcpy(buf, mem->buffer, sizeof(char) * size); + mem->pos += size; + + return size; +} + +static int writefn(void *handler, const char *buf, int size) { + fmem_t *mem = handler; + size_t available = mem->size - mem->pos; + + if (size > available) { + size = available; + } + memcpy(mem->buffer, buf, sizeof(char) * size); + mem->pos += size; + + return size; +} + +static fpos_t seekfn(void *handler, fpos_t offset, int whence) { + size_t pos; + fmem_t *mem = handler; + + switch (whence) { + case SEEK_SET: pos = offset; break; + case SEEK_CUR: pos = mem->pos + offset; break; + case SEEK_END: pos = mem->size + offset; break; + default: return -1; + } + + if (pos > mem->size) { + return -1; + } + + mem->pos = pos; + return (fpos_t)pos; +} + +static int closefn(void *handler) { + free(handler); + return 0; +} + +FILE *fmemopen(void *buf, size_t size, const char *mode) { + // This data is released on fclose. + fmem_t* mem = (fmem_t *) malloc(sizeof(fmem_t)); + + // Zero-out the structure. + memset(mem, 0, sizeof(fmem_t)); + + mem->size = size; + mem->buffer = buf; + + // funopen's man page: https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/funopen.3.html + return funopen(mem, readfn, writefn, seekfn, closefn); +} diff --git a/fmemopen.h b/fmemopen.h new file mode 100755 index 0000000..7d6679f --- /dev/null +++ b/fmemopen.h @@ -0,0 +1,43 @@ +// +// Copyright 2012 Jeff Verkoeyen +// Originally ported from https://github.com/ingenuitas/python-tesseract/blob/master/fmemopen.c +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef FMEMOPEN_H_ +#define FMEMOPEN_H_ + +/** + * A BSD port of the fmemopen Linux method using funopen. + * + * man docs for fmemopen: + * http://linux.die.net/man/3/fmemopen + * + * man docs for funopen: + * https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/funopen.3.html + * + * This method is ported from ingenuitas' python-tesseract project. + * + * You must call fclose on the returned file pointer or memory will be leaked. + * + * @param buf The data that will be used to back the FILE* methods. Must be at least + * @c size bytes. + * @param size The size of the @c buf data. + * @param mode The permitted stream operation modes. + * @returns A pointer that can be used in the fread/fwrite/fseek/fclose family of methods. + * If a failure occurred NULL will be returned. + */ +FILE *fmemopen(void *buf, size_t size, const char *mode); + +#endif // #ifndef FMEMOPEN_H_