#include #include "assert.h" #include "english.h" #include "errors/errors.h" #include "errors/exceptions.h" #include "files/buffer.h" #include "files/files.h" #include "files/filters/filters.h" #include "files/filters/methods.h" #include "files/filters/parameters.h" #include "memory/virtualmemory.h" #include "object.h" #include "operators/operands.h" #include "types/attributes.h" #include "types/boolean.h" #include "types/composites/composites.h" #include "types/composites/load.h" #include "types/equality.h" static object (*decoder(const filtername filter))(object, object) { static object (* const decoder[allfilternames])(object, object) = { [ASCII85Decode] = ASCII85Decoder, [ASCIIHexDecode] = ASCIIHexDecoder, [CryptDecode] = CryptDecoder, [EexecDecode] = EexecDecoder, [LineDecode] = StatementDecoder, [LiteralTextDecode] = LiteralTextDecoder, [NullDecode] = NullDecoder, [ReusableStreamDecode] = ReusableStreamDecoder, [StatementDecode] = StatementDecoder, [SubFileDecode] = SubFileDecoder }; assert(filter < sizeof decoder / sizeof *decoder); return decoder[filter]; } static void (*encoder(const filtername filter))(object, object) { static void (* const encoder[allfilternames])(object, object) = { [ASCII85Encode] = ASCII85Encoder, [ASCIIHexEncode] = ASCIIHexEncoder, [LineWrappingEncode] = LineWrappingEncoder, [LiteralTextEncode] = LiteralTextEncoder, [NullEncode] = NullEncoder }; assert(filter < sizeof encoder / sizeof *encoder); return encoder[filter]; } boolean filteroperator(const filtername filter) { static const boolean filteroperator[allfilternames] = { [ASCII85Decode] = true, [ASCII85Encode] = true, [ASCIIHexDecode] = true, [ASCIIHexEncode] = true, [NullEncode] = true, [ReusableStreamDecode] = true, [SubFileDecode] = true }; assert(filter < sizeof filteroperator / sizeof *filteroperator); return filteroperator[filter]; } filtername lookupfilter(const object name) { assert(name.type == nametype); static const struct {object string; filtername filter;} list[allfilternames] = { #define each(FILTER) as \ {stringliteral(#FILTER), FILTER}, foreach (filter) #undef FILTER }; for (size_t entry = 0; entry < sizeof list / sizeof *list; ++entry) { if (eq(name, list[entry].string)) return list[entry].filter; } throw (undefined); } struct filteroperands filteroperands(const filtername index, object *operand, const object filterparameters) { static struct filteroperands (* const filteroperands_[allfilternames])(object *, object) = { [DCTEncode] = DCTEncodeoperands, [RunLengthEncode] = RunLengthEncodeoperands, [SubFileDecode] = SubFileDecodeoperands }; assert(index < sizeof filteroperands_ / sizeof *filteroperands_); if (filteroperands_[index]) { const struct filteroperands parameters = filteroperands_[index](operand, filterparameters); if (parameters.operand[1].type == dicttype) parameters.dictionary.array[filterdict] = parameters.operand[1]; return parameters; } else { if (operand[0].type == dicttype) operand = require(operandstack, anytype, dicttype, nametype); return (struct filteroperands){ .operand = operand, .dictionary = filterparameters }; } } object createfilter(const filtername filtername, const object thing) { assert(filtername < allfilternames); object file = createfile(copy[arraytype]( filter(filtername, (thing.type == filetype) ? thing : createfile(thing)), create[arraytype](filterarray) )); file.array[bufferstring] = (object){.type = stringtype}; file.access = decoder(filtername) ? readonly : unlimited; return file; } object getparameter(const object name, const object parameters) { assert(parameters.type == arraytype); assert(parameters.access == readonly); assert(parameters.length == FilterParameters); assert(parameters.array); if (parameters.array[filterdict].type == dicttype) { const object * const value = known(name, parameters.array[filterdict]); if (value) return *value; } else { assert(parameters.array[filterdict].type == nulltype); } return null; } object openDecoder(const filtername filtername, object source, const object parameters) { if (source.access > executeonly) throw (invalidaccess); object CloseSource = getparameter(string("CloseSource"), parameters); switch (CloseSource.type) { case nulltype: CloseSource = boolean(false); case booleantype: break; default: throw (typecheck); } const boolean previous = vm.allocationmode; vm.allocationmode = global(source); const object file = createfilter(filtername, source); vm.allocationmode = previous; file.array[stream].array[filterparameters] = CloseSource; return file; } object openEncoder(const filtername filtername, object target, const object parameters) { if (target.access > unlimited) throw (invalidaccess); object CloseTarget = getparameter(string("CloseTarget"), parameters); switch (CloseTarget.type) { case nulltype: CloseTarget = boolean(false); case booleantype: break; default: throw (typecheck); } const boolean previous = vm.allocationmode; vm.allocationmode = global(target); const object file = createfilter(filtername, target); if (target.isexecutable && (target.type == arraytype || target.type == packedarraytype)) file.array[stream].array[bufferstring] = (object){.type = stringtype}; vm.allocationmode = previous; file.array[stream].array[filterparameters] = CloseTarget; return file; } object openfilter(const filtername index, const object stream, const object parameters) { static object (* const openfilter[allfilternames])(filtername, object, object) = { [ASCII85Decode] = openDecoder, [ASCII85Encode] = openLineWrappingEncoder, [ASCIIHexDecode] = openDecoder, [ASCIIHexEncode] = openLineWrappingEncoder, [CryptDecode] = openCryptDecoder, [EexecDecode] = openCryptDecoder, [LineDecode] = openDecoder, [LiteralTextDecode] = openDecoder, [LiteralTextEncode] = openEncoder, [NullDecode] = openDecoder, [NullEncode] = openEncoder, [ReusableStreamDecode] = openReusableStreamDecoder, [StatementDecode] = openDecoder, [SubFileDecode] = openSubFileDecoder }; assert(index < sizeof openfilter / sizeof *openfilter); assert(openfilter[index]); switch (stream.type) { case filetype: case stringtype: { break; } case arraytype: case packedarraytype: { if (stream.isexecutable) break; } default: { throw (typecheck); } } assert(parameters.type == arraytype); assert(parameters.access == readonly); assert(parameters.length == FilterParameters); assert(parameters.array); if (parameters.array[filterdict].type != dicttype) assert(parameters.array[filterdict].type == nulltype); return buffered(openfilter[index](index, stream, parameters)); } void closefilter(const object file) { static void (* const closefilter_[allfilternames])(object) = { [ASCII85Encode] = closeASCII85Encoder, [ASCIIHexEncode] = closeASCIIHexEncoder, [LineDecode] = closeStatementDecoder, [LiteralTextEncode] = closeLiteralTextEncoder, [ReusableStreamDecode] = closeReusableStreamDecoder, [StatementDecode] = closeStatementDecoder }; const object instance = streamfrom(file); assert(instance.type == arraytype); assert(instance.length == filterarray); assert(instance.array); if (instance.array[filter].type == integertype) { assert(instance.array[filter].integer >= 0); assert(instance.array[filter].integer < allfilternames); const filtername filtername = (enum filtername)instance.array[filter].integer; assert(filtername < sizeof closefilter_ / sizeof *closefilter_); if (closefilter_[filtername]) closefilter_[filtername](file); } else { assert(instance.array[filter].type == nulltype); } object closestream = boolean(false); if (instance.array[filterparameters].type == booleantype) { closestream = instance.array[filterparameters]; } else if (instance.array[filterparameters].type == arraytype) { assert(instance.array[filterparameters].length >= allCloseStreamParameters); assert(instance.array[filterparameters].array); closestream = instance.array[filterparameters].array[CloseStream]; for (natural index = 0; index < instance.array[filterparameters].length; ++index) instance.array[filterparameters].array[index] = null; } const object underlying = instance.array[stream]; for (natural index = 0; index < instance.length; ++index) instance.array[index] = null; if (closestream.type == booleantype && closestream.boolean) { if (underlying.type == filetype) closefile(underlying); } } static filtername filternamefrom(const object instance) { assert(instance.type == arraytype); assert(instance.length == filterarray); assert(instance.array); if (instance.array[filter].type == integertype) { assert(instance.array[filter].integer >= 0); assert(instance.array[filter].integer < allfilternames); return (filtername)instance.array[filter].integer; } else { throw (ioerror); } } object decode(const object instance, const object string) { object (* const decode)(object, object) = decoder(filternamefrom(instance)); if (decode) return decode(instance, string); else throw (ioerror); } void encode(const object string, const object instance) { void (* const encode)(object, object) = encoder(filternamefrom(instance)); if (encode) encode(string, instance); else throw (ioerror); } void discardfilter(const object instance) { static void (* const discardfilter_[allfilternames])(object) = { [ReusableStreamDecode] = discardReusableStreamDecoder }; const filtername filter = filternamefrom(instance); assert(filter < sizeof discardfilter_ / sizeof *discardfilter_); if (discardfilter_[filter]) { discardfilter_[filter](instance); } else { if (decoder(filter)) { for (object discard = memory(buffersize); decode(instance, discard).length;) continue; } } } boolean endoffilter(const object instance) { typedef boolean function(object); static function * const endoffilter_[allfilternames] = { [ReusableStreamDecode] = endofReusableStreamDecoder }; const filtername filter = filternamefrom(instance); assert(filter < sizeof endoffilter_ / sizeof *endoffilter_); if (endoffilter_[filter]) return endoffilter_[filter](instance); else return true; } void resetfilefilter(const object instance) { static void (* const resetfilefilter_[allfilternames])(object) = { [ReusableStreamDecode] = resetfileReusableStreamDecoder }; const filtername filter = filternamefrom(instance); assert(filter < sizeof resetfilefilter_ / sizeof *resetfilefilter_); if (resetfilefilter_[filter]) resetfilefilter_[filter](instance); } void setfilepositionfilter(const object instance, const integer position) { static void (* const setfilepositionfilter_[allfilternames])(object, integer) = { [ReusableStreamDecode] = setfilepositionReusableStreamDecoder }; const filtername filter = filternamefrom(instance); assert(filter < sizeof setfilepositionfilter_ / sizeof *setfilepositionfilter_); if (setfilepositionfilter_[filter]) setfilepositionfilter_[filter](instance, position); else throw (ioerror); } integer bytesavailablefilter(const object instance) { typedef integer function(object); static function * const bytesavailablefilter_[allfilternames] = { [LineDecode] = bytesavailableStatementDecoder, [ReusableStreamDecode] = bytesavailableReusableStreamDecoder, [StatementDecode] = bytesavailableStatementDecoder }; const filtername filter = filternamefrom(instance); assert(filter < sizeof bytesavailablefilter_ / sizeof *bytesavailablefilter_); if (bytesavailablefilter_[filter]) return bytesavailablefilter_[filter](instance); else return -1; } integer filepositionfilter(const object instance) { typedef integer function(object); static function * const filepositionfilter_[allfilternames] = { [ReusableStreamDecode] = filepositionReusableStreamDecoder }; const filtername filter = filternamefrom(instance); assert(filter < sizeof filepositionfilter_ / sizeof *filepositionfilter_); if (filepositionfilter_[filter]) return filepositionfilter_[filter](instance); else throw (ioerror); }